﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using HalconDotNet;
using System.Drawing;
using System.Windows.Forms;
using DCP;
using Algorithms;
using SBBitmap;
using SimpleCADControl.GeoObjects;


namespace cellAnalysis
{
    public struct DoublePoint
    {
        public double X;
        public double Y;
    }
    public struct nodesData
    {
        public PathFinderNode node;
        //public List<Point> SCP_Distances;
        public IOrderedEnumerable<DCPData> dist_Sorted_SCP_List;
    }
    public struct DCPData
    {
        //Distanz zum bestimmten node
        public double nodeDistance;
        //Nächstgelegener gültiger Node
        public PathFinderNode node;
        //X-Pos des SCP
        public double X;
        //Y-Pos des SCP
        public double Y;
    }
    public struct cellAndHolesContPoints
    {
        public SimpleCADControl.Vector2D[] cellContourPoints;
        public List<SimpleCADControl.Vector2D[]> cellHolesContourPoints;
    }
    public static class HalObjToCADControl
    {
        public static SimpleCADControl.GeoObjects.Polygon CreatePoly(SimpleCADControl.Vector2D[] contourPoints)
        {
            SimpleCADControl.GeoObjects.Polygon poly = new SimpleCADControl.GeoObjects.Polygon(contourPoints);
            return poly;
        }
        public static SimpleCADControl.Vector2D[] createCADContourPoints(HObject region)
        {
            HTuple rows, cols;

            HOperatorSet.GetRegionContour(region, out rows, out cols);
            //Wenn ein Rest nach der Teilung existiert muss die Länge des Arrays um 1 erhöht werden
            SimpleCADControl.Vector2D[] contourPoints = new SimpleCADControl.Vector2D[rows.Length];
            for (int j = 0; j < rows.Length; j++)
            {
                SimpleCADControl.Vector2D vec = new SimpleCADControl.Vector2D(cols[j].D, rows[j].D);
                contourPoints[j] = vec;
            }
            return contourPoints;
        }
        public static SimpleCADControl.Vector2D[] createCADContourPoints(HObject region, int x)
        {
            HTuple rows, cols;

            HOperatorSet.GetRegionContour(region, out rows, out cols);
            //Wenn ein Rest nach der Teilung existiert muss die Länge des Arrays um 1 erhöht werden
            while (rows.Length / x + (rows.Length % x == 0 ? 0 : 1) < 3)
            {
                x--;
            }
            SimpleCADControl.Vector2D[] contourPoints = new SimpleCADControl.Vector2D[rows.Length / x + (rows.Length % x == 0 ? 0 : 1)];
            for (int j = 0; j < rows.Length; j += x)
            {
                SimpleCADControl.Vector2D vec = new SimpleCADControl.Vector2D(cols[j].D, rows[j].D);
                contourPoints[j / x] = vec;
            }
            return contourPoints;
        }
        public static List<SimpleCADControl.Vector2D[]> createCADContourPointsList(HObject regions, int x)
        {
            HTuple rows, cols;
            HObject selectedRegion;

            List<SimpleCADControl.Vector2D[]> contoursList = new List<SimpleCADControl.Vector2D[]>();

            for (int i = 0; i < regions.CountObj(); i++)
            {
                HOperatorSet.SelectObj(regions, out selectedRegion, i + 1);
                HOperatorSet.GetRegionContour(selectedRegion, out rows, out cols);
                //HOperatorSet.GetRegionPoints(selectedRegion, out rows, out cols);
                //Wenn ein Rest nach der Teilung existiert muss die Länge des Arrays um 1 erhöht werden
                SimpleCADControl.Vector2D[] contourPoints = new SimpleCADControl.Vector2D[rows.Length / x + (rows.Length % x == 0 ? 0 : 1)];
                for (int j = 0; j < rows.Length; j += x)
                {
                    SimpleCADControl.Vector2D vec = new SimpleCADControl.Vector2D(cols[j].D, rows[j].D);
                    contourPoints[j / x] = vec;
                }
                contoursList.Add(contourPoints);
            }
            return contoursList;
        }
        //Gibt eine Liste
        public static List<cellAndHolesContPoints> createCADContourPointsListList(List<cellData> cells, int stepCells, int stepHoles, HWindow window)
        {
            HTuple rows, cols;
            int stepHoles_Temp;
            stepHoles_Temp = stepHoles;

            //HObject connectedReg;

            List<cellAndHolesContPoints> cellAndHolesContPoints = new List<cellAndHolesContPoints>();
            SimpleCADControl.Vector2D[] contourPointsHole;

            for (int i = 0; i < cells.Count; i++)
            {
                cellAndHolesContPoints newItem = new cellAndHolesContPoints();
                HOperatorSet.GetRegionContour(cells[i].cellRegion, out rows, out cols);
                //HOperatorSet.Connection(cells[i].cellRegion, out connectedReg);
                //HOperatorSet.SetColored(window, 12);
                //HOperatorSet.DispObj(connectedReg, window);
                //MessageBox.Show("Test");
                //Wenn ein Rest nach der Teilung existiert muss die Länge des Arrays um 1 erhöht werden
                SimpleCADControl.Vector2D[] contourPoints = new SimpleCADControl.Vector2D[rows.Length / stepCells + (rows.Length % stepCells == 0 ? 0 : 1)];
                for (int j = 0; j < rows.Length; j += stepCells)
                {
                    SimpleCADControl.Vector2D vec = new SimpleCADControl.Vector2D(cols[j].D, rows[j].D);
                    contourPoints[j / stepCells] = vec;
                }
                newItem.cellContourPoints = contourPoints;

                //Löcherkonturpunkte für die aktuelle Zelle berechnen

                List<SimpleCADControl.Vector2D[]> holesContourList = new List<SimpleCADControl.Vector2D[]>();

                if (cells[i].cellHoles != null)
                {
                    for (int j = 0; j < cells[i].cellHoles.Length; j++)
                    {
                        HOperatorSet.GetRegionContour(cells[i].cellHoles[j], out rows, out cols);
                        //Falls Löcherkonturen mit weniger als 3 Pixel existieren werden diese nicht berücksichtigt
                        if (rows.Length > 2)
                        {
                            //Wenn ein Rest nach der Teilung existiert muss die Länge des Arrays um 1 erhöht werden

                            //Wenn der step zu groß gewählt ist und bei dem Loch weniger als 3 Konturpunkte resultieren muss
                            //für dieses kleine Loch der step angepasst werden
                            if (rows.Length / stepHoles + (rows.Length % stepHoles == 0 ? 0 : 1) < 3)
                            {
                                stepHoles--;
                                while (rows.Length / stepHoles + (rows.Length % stepHoles == 0 ? 0 : 1) < 3)
                                {
                                    stepHoles--;
                                }
                                contourPointsHole = new SimpleCADControl.Vector2D[rows.Length / stepHoles + (rows.Length % stepHoles == 0 ? 0 : 1)];
                            }
                            else
                                contourPointsHole = new SimpleCADControl.Vector2D[rows.Length / stepHoles + (rows.Length % stepHoles == 0 ? 0 : 1)];
                            for (int k = 0; k < rows.Length; k += stepHoles)
                            {
                                SimpleCADControl.Vector2D vec = new SimpleCADControl.Vector2D(cols[k].D, rows[k].D);
                                contourPointsHole[k / stepHoles] = vec;
                            }
                            holesContourList.Add(contourPointsHole);
                            stepHoles = stepHoles_Temp;
                        }
                    }
                    newItem.cellHolesContourPoints = holesContourList;
                }
                cellAndHolesContPoints.Add(newItem);
            }
            return cellAndHolesContPoints;
        }
        public static cellAndHolesContPoints createCADContourPointsList(cellData cell, int stepCell, int stepHoles)
        {
            HTuple rows, cols;

            cellAndHolesContPoints cellAndHolesContPoints = new cellAndHolesContPoints();

            HOperatorSet.GetRegionContour(cell.cellRegion, out rows, out cols);
            //Wenn ein Rest nach der Teilung existiert muss die Länge des Arrays um 1 erhöht werden
            SimpleCADControl.Vector2D[] contourPoints = new SimpleCADControl.Vector2D[rows.Length / stepCell + (rows.Length % stepCell == 0 ? 0 : 1)];
            for (int j = 0; j < rows.Length; j += stepCell)
            {
                SimpleCADControl.Vector2D vec = new SimpleCADControl.Vector2D(cols[j].D, rows[j].D);
                contourPoints[j / stepCell] = vec;
            }
            cellAndHolesContPoints.cellContourPoints = contourPoints;

            //Löcherkonturpunkte für die aktuelle Zelle berechnen

            List<SimpleCADControl.Vector2D[]> holesContourList = new List<SimpleCADControl.Vector2D[]>();

            if (cell.cellHoles != null)
            {
                for (int j = 0; j < cell.cellHoles.Length; j++)
                {
                    HOperatorSet.GetRegionContour(cell.cellHoles[j], out rows, out cols);
                    //Falls Löcherkonturen mit weniger als 3 Pixel existieren werden diese nicht berücksichtigt
                    if (rows.Length > 2)
                    {
                        //Wenn ein Rest nach der Teilung existiert muss die Länge des Arrays um 1 erhöht werden
                        SimpleCADControl.Vector2D[] contourPointsHole = new SimpleCADControl.Vector2D[rows.Length / stepHoles + (rows.Length % stepHoles == 0 ? 0 : 1)];
                        for (int k = 0; k < rows.Length; k += stepHoles)
                        {
                            SimpleCADControl.Vector2D vec = new SimpleCADControl.Vector2D(cols[k].D, rows[k].D);
                            contourPointsHole[k / stepHoles] = vec;
                        }
                        holesContourList.Add(contourPointsHole);
                    }
                }
                cellAndHolesContPoints.cellHolesContourPoints = holesContourList;
            }
            return cellAndHolesContPoints;
        }
    }
    public class cellStatistics
    {
        public double cellArea;
        public double circularity;
        public double saturation;
        public double saturationDeviation;
        public double cellForm;
        public int coreCount;
        public int numberCellExt;
        public double endoEktoRatio;
    }
    public class cellCoreData
    {
        public HObject cellCore;
        public DoublePoint SP;
        public bool isDarkCore;
        public SimpleCADControl.GeoObjects.Polygon cellCoreContour;
    }
    public class cellData
    {
        public cellAndHolesContPoints contourPoints;
        public HObject cellRegion;
        public HObject[] cellHoles;
        public SimpleCADControl.GeoObjects.Polygon cellContour;
        public List<cellCoreData> CoreInfo;
        public cellStatistics statistics;
        public bool isAlive;
        public bool isCluster;
        public bool wasBarbelCell;
        public int nr;
    }
    public static class CellCoreWorker
    {
        /// <summary>
        /// ZELLKERNREGIONEN BEARBEITEN -> HAL-REGIONEN ERZEUGEN
        ///                                       -> OPENING ZUR TRENNUNG ZUSAMMENGEWACHSENER ZELLKERNE
        ///                                       -> ZELLKERNBEREICHE DIE AUSSERHALB DES ZELLBEREICHES LIEGEN ELIMINIEREN
        ///                                       -> PRÜFEN OB ZELLKERN-SP INNERHALB DER ZELLKERNREGION LIEGT
        ///                                          WENN NICHT DANN SP DES GRÖSSTEN INNENKREISES ALS ZK-SP SETZEN
        ///                                       -> GEMEINSAME SCHNITTMENGE VERSCHIEDENER KERNE VON KERNREGIONEN
        ///                                          SUBTRAHIEREN
        /// </summary>
        public static List<cellData> EditCellCores(HWindow window, HObject OrgImg, TImage CoreImage, List<cellData> cells, int minCoreArea, out HObject RegionTemplateR, out HObject RegionTemplateG)
        {
            HObject TargetImg;
            //HObject OrgImg;

            CoreImage.Image.Save(Application.StartupPath + "\\coresImg.bmp", System.Drawing.Imaging.ImageFormat.Bmp);
            HOperatorSet.ReadImage(out TargetImg, Application.StartupPath + "\\coresImg.bmp");
            //HalconDotNet.HOperatorSet.GenImageInterleaved(out TargetImg, CoreImage.firstPixel, "bgr",
            //                  CoreImage.Width, CoreImage.Height, 0, "byte",
            //                  0, 0, 0, 0, -1, 0);
            //HalconDotNet.HOperatorSet.GenImageInterleaved(out OrgImg, SourceImage.firstPixel, "bgr",
            //                                  SourceImage.Width, SourceImage.Height, 0, "byte",
            //                                  0, 0, 0, 0, -1, 0);

            List<cellCoreData> selectedCores, selectedCoresOpened, validCoresOpened, validCoresSeparatedIfMelted;
            List<cellData> preCellsWithCores;

            //Berechnet aus dem Ergebnisbild des HB-Algorithmus die Zellkernregionen
            CellCoreWorker.CreateCoreRegions(window, OrgImg, TargetImg, minCoreArea, out selectedCores, out RegionTemplateR, out RegionTemplateG);

            //MessageBox.Show("cores");

            //Führt ein Opening der Zellkernregionen durch um teilweise zu einer Region verbundene
            //verschiedene Zellkerne wieder zu trennen
            CellCoreWorker.OpeningCoreRegions(selectedCores, cells, minCoreArea, out selectedCoresOpened);


            //Prüfen ob Zellkernbereiche ausserhalb von Zellbereichen liegen. Ausserhalb liegende Zellkernbereiche 
            //eliminieren
            selectedCoresOpened = CellCoreWorker.DeleteInvalidCoreAreas(cells, selectedCoresOpened);

            //HOperatorSet.SetDraw(window, "fill");
            //HOperatorSet.SetColor(window, "green");
            //for (int i = 0; i < selectedCoresOpened.Count; i++)
            //{
            //    HOperatorSet.DispObj(selectedCoresOpened[i].cellCore, window);
            //}
            //MessageBox.Show("cores 2");

            //Zellkernschwerpunkte prüfen, ob sie innerhalb der Zellregion liegen
            //Wenn nicht, dann SP durch Mittelpunkt des größten Innenkreises des Kerns ersetzen
            CellCoreWorker.checkCoresSP(selectedCoresOpened, cells, out validCoresOpened, window);

            //HOperatorSet.SetColor(window, "orange");
            //for (int i = 0; i < validCoresOpened.Count; i++)
            //{
            //    HOperatorSet.DispObj(validCoresOpened[i].cellCore, window);
            //}
            //MessageBox.Show("cores 3");

            //Prüfen ob es Kerne gibt, die eine gemeinsame Schnittmenge haben. Wenn ja, dann die gemeinsame Schnitt
            //menge von den Kernregionen subtrahieren
            CellCoreWorker.checkCoresIntersectionRegion(validCoresOpened, out validCoresSeparatedIfMelted);

            HOperatorSet.SetDraw(window, "margin");

            for (int i = 0; i < validCoresSeparatedIfMelted.Count; i++)
            {
                HOperatorSet.SetColor(window, "yellow");
                HOperatorSet.DispObj(validCoresSeparatedIfMelted[i].cellCore, window);
            }

            //Die ermittelten Zellkerne nun den Zellen zuordnen
            CellCoreWorker.assignCoresToCells(validCoresSeparatedIfMelted, cells, out preCellsWithCores);

            return preCellsWithCores;
        }
        public static class DecisionTreeCoreSegmentation
        {
            private struct coreData
            {
                public HObject core;
                public bool isDarkCore;
            }
            //Schwellwert ab wann ein Zellbereich groß ist
            public static int m_threshBigCell = 10000;
            //Schwellwert ab wann ein heller Kernbereich groß ist
            //da große dunkle Kernbereiche durchaus neben mittelgroßen oder
            //kleineren hellen Kernbereichen liegen können, nicht aber neben
            //einem großen hellen Kernbereich
            public static int m_threshBigBrightCore = 2000;
            //Schwellwert ab wann ein dunkler Kernbereich groß ist
            public static int m_threshBigDarkCore = 2000;
            //Schwellwert, bis welche Entfernung 2 Zellkerne Nachbarn sind
            public static int m_neighbourDistance = 200;
            //Schwellwert, ab welchem Verhältnis von Templatefläche R zu Templatefläche G
            //man von einem dunklen Zellkernbereich spricht
            public static double m_threshDarkCore = 20;

            private static bool isBigCell(HObject cellRegion)
            {
                HTuple area, row, col;
                HOperatorSet.AreaCenter(cellRegion, out area, out row, out col);
                if (area.I >= m_threshBigCell)
                    return true;
                else
                    return false;
            }
            private static bool isBigCore(HObject CoreRegion, bool isDarkCore)
            {
                HTuple area, row, col;
                HOperatorSet.AreaCenter(CoreRegion, out area, out row, out col);
                if (isDarkCore == true)
                {
                    if (area.I >= m_threshBigDarkCore)
                        return true;
                    else
                        return false;
                }
                else
                {
                    if (area.I >= m_threshBigBrightCore)
                        return true;
                    else
                        return false;
                }
            }
            private static bool neighbouringCores(HObject core1, HObject core2)
            {
                HTuple area1, row1, col1;
                HTuple area2, row2, col2;
                double dist;
                HOperatorSet.AreaCenter(core1, out area1, out row1, out col1);
                HOperatorSet.AreaCenter(core2, out area2, out row2, out col2);

                dist = Math.Sqrt((row1 - row2) * (row1 - row2) + ((col2 - col1) * (col2 - col1)));
                if (dist < m_neighbourDistance)
                    return true;
                else
                    return false;
            }
            private static bool isDarkCore(HObject core, HObject regionTemplateR, HObject regionTemplateG)
            {
                HObject regionIntersectionR, regionIntersectionG;
                HTuple areaR, rowR, colR, areaG, rowG, colG;

                try
                {
                    double templateQuotient = -1.0;

                    HOperatorSet.Intersection(core, regionTemplateR, out regionIntersectionR);
                    HOperatorSet.Intersection(core, regionTemplateG, out regionIntersectionG);

                    HOperatorSet.AreaCenter(regionIntersectionR, out areaR, out rowR, out colR);
                    HOperatorSet.AreaCenter(regionIntersectionG, out areaG, out rowG, out colG);
                    if (areaG == 0)
                        return true;
                    if (areaR == 0)
                        return false;
                    templateQuotient = areaR.D / areaG.D;
                    if (templateQuotient > m_threshDarkCore)
                        return true;
                    else
                        return false;
                }
                catch (System.Exception ex)
                {
                    return true;
                }

            }
            private static bool dark_and_bright_core(List<cellCoreData> CoresInCell)
            {
                bool dark = false;
                bool bright = false;

                for (int i = 0; i < CoresInCell.Count; i++)
                {
                    if (CoresInCell[i].isDarkCore)
                        dark = true;
                    else
                        bright = true;
                }
                if ((dark == true) && (bright == true))
                    return true;
                else
                    return false;
            }
            //Löschen von falsch segmentierten Zellkernbereichen in großen Zellclustern (<10.000Pix),
            //Ein falscher Zellkern ist ein Zellkernbereich der zum Großteil aus dunklem Zellkernmaterial besteht,
            //und relativ groß ist und relativ nahe an einem helleren Zellkern angrenzt
            private static void invalid_Core_deleting(List<cellData> cells, HObject regionTemplateR, HObject regionTemplateG, out List<cellData> validCoresInCells)
            {
                HObject remainingCellCores;
                //Liste die die Indexe der Kerne speichert, die am Ende aus der Liste
                //gelöscht werden, weil sie keine gültigen Zellkerne sind
                List<int> indexList = new List<int>();
                //List<cellData> validCoresInCells_internal = new List<cellData>();
                List<cellData> validCoresInCells_internal = new List<cellData>();

                HOperatorSet.GenEmptyObj(out remainingCellCores);

                //Für jede segmentierte Zelle prüfen ob Zellkerne enthalten sind
                //Wenn ja, dann die Zellkerne mit Regeln prüfen
                for (int i = 0; i < cells.Count; i++)
                {
                    indexList.Clear();
                    //Einzelne Zellkerne in der Zelle prüfen ob sie dunkle Farbbereiche besitzen
                    for (int j = 0; j < cells[i].CoreInfo.Count; j++)
                    {
                        cellCoreData core = new cellCoreData();
                        core.cellCore = cells[i].CoreInfo[j].cellCore;
                        core.SP.X = cells[i].CoreInfo[j].SP.X;
                        core.SP.Y = cells[i].CoreInfo[j].SP.Y;
                        core.isDarkCore = isDarkCore(cells[i].CoreInfo[j].cellCore, regionTemplateR, regionTemplateG);
                        cells[i].CoreInfo.Insert(j + 1, core);
                        cells[i].CoreInfo.RemoveAt(j);
                    }
                    //Prüfen ob mind. ein dunkler Zellkern vorhanden ist, wenn mind. 2 Zellkerne insgesamt vorhanden sind
                    if (cells[i].CoreInfo.Count >= 1)
                    {
                        //Prüfen ob die Zelle bzw. der Zellcluster eine Fläche > 10.000Pix besitzt
                        if (isBigCell(cells[i].cellRegion))
                        {
                            //Prüfen, ob mind. 1 dunkler Zellkern und 1 hellerer Zellkern in der Zelle, bzw. Cluster
                            //vorhanden ist
                            if (dark_and_bright_core(cells[i].CoreInfo))
                            {
                                //Prüfen ob der/die dunklen Zellkerne relativ groß sind
                                for (int j = 0; j < cells[i].CoreInfo.Count; j++)
                                {
                                    if (cells[i].CoreInfo[j].isDarkCore == true)
                                    {
                                        if (isBigCore(cells[i].CoreInfo[j].cellCore, true) == true)
                                        {
                                            //Prüfen ob der große dunkle Zellkern in der Nähe eines helleren
                                            //Zellkerns liegt. Wenn dies der Fall ist, dann handelt es sich um 
                                            //einen falsch segmentierten Zellkern, da wir nicht davon ausgehen, dass
                                            //dunkle große Zellkerne nahe an hellen Zellkernen liegen. Wenn dann sind die 
                                            //dunklen Zellkerne eher kleiner, da sich kleine Zellen an große angeheftet haben
                                            bool alreadyinserted = false;
                                            for (int k = 0; k < cells[i].CoreInfo.Count; k++)
                                            {
                                                if ((cells[i].CoreInfo[k].isDarkCore == false) && (isBigCore(cells[i].CoreInfo[k].cellCore, false) == true))
                                                {
                                                    if ((neighbouringCores(cells[i].CoreInfo[j].cellCore, cells[i].CoreInfo[k].cellCore) && (alreadyinserted == false)))
                                                    {
                                                        indexList.Add(j);
                                                        alreadyinserted = true;
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                    //ungültige Zellkerne aus der Liste löschen...
                    for (int k = 0; k < indexList.Count; k++)
                    {
                        cells[i].CoreInfo.RemoveAt(indexList[k]);
                    }
                }
                validCoresInCells = cells;
            }
            public static void checkCellCores(List<cellData> cells, HObject regionTemplateR, HObject regionTemplateG, out List<cellData> validCoresInCells)
            {
                invalid_Core_deleting(cells, regionTemplateR, regionTemplateG, out validCoresInCells);
            }
            //Zellkernbereiche in Einzelzellen >= 7.000, die eine Fläche < 1000 Pix aufweisen werden gelöscht
            //da die Bereiche als Kern fehlklassifiziert wurden
            public static void deleting_to_small_Cores(List<cellData> cells, out List<cellData> validCellCores)
            {
                HTuple area, row, col;
                List<cellData> validCellCores_internal = new List<cellData>();

                //Alle Einzel-Zellen durchlaufen
                for (int i = 0; i < cells.Count; i++)
                {
                    if (cells[i].isCluster == false)
                    {
                        //Wenn die Fläche einer Zelle >=7.000Pix ist, Zellkernregionen < 1000 Pix eliminieren
                        //da es sich um keine richtigen Zellkerne handelt
                        HOperatorSet.AreaCenter(cells[i].cellRegion, out area, out row, out col);
                        if (area.I >= 7000)
                        {
                            for (int j = 0; j < cells[i].CoreInfo.Count; j++)
                            {
                                HOperatorSet.AreaCenter(cells[i].CoreInfo[j].cellCore, out area, out row, out col);
                                //Notlösung gerade, solange die Klassifizierung nicht perfekt ist
                                //Solange weniger als 3 Kerne in einer Zelle bzw. einem Zellcluster vorhanden
                                //sind die Kerne < 1000Pix und relativ nahe an einen anderem Kern (<200Pix) löschen, andernfalls nicht löschen
                                if ((area < 1000) && (cells[i].CoreInfo.Count == 2))
                                {
                                    if (neighbouringCores(cells[i].CoreInfo[0].cellCore, cells[i].CoreInfo[1].cellCore) == true)
                                        cells[i].CoreInfo.RemoveAt(j);
                                }
                            }
                        }
                    }
                }
                validCellCores = cells;
            }
        }
        public static void CreateCoreRegions(HWindow window, HObject CellImg, HObject TargetImg, int minCoreArea, out List<cellCoreData> selectedCoreRegions, out HObject RegionTemplateR, out HObject RegionTemplateG)
        {
            // Local iconic variables 
            HObject backgroundRegion;
            HObject ho_ImageR, ho_ImageG, ho_ImageB;
            HObject selectedCoreRegions_HAL, selectedCore;
            HObject ho_RegionR, ho_RegionG, ho_ConnectedRegionsR, ho_ConnectedRegionsG;
            HObject ho_SelectedRegionsR, ho_SelectedRegionsG, ho_RegionDilationR, ho_RegionDilationG;
            HObject ho_RegionUnionR, ho_RegionUnionG, ho_RegionUnion, ho_RegionUnion1;
            HObject ho_RegionDilation, ho_RegionErosion, ho_ConnectedFilledRegion, ho_RegionFillUp, selectedCoreRegionsFinal_HAL;
            List<cellCoreData> selectedCoreRegions_internal = new List<cellCoreData>();

            // Initialize local and output iconic variables 
            HOperatorSet.GenEmptyObj(out ho_ImageR);
            HOperatorSet.GenEmptyObj(out ho_ImageG);
            HOperatorSet.GenEmptyObj(out ho_ImageB);
            HOperatorSet.GenEmptyObj(out ho_RegionR);
            HOperatorSet.GenEmptyObj(out ho_RegionG);
            HOperatorSet.GenEmptyObj(out ho_ConnectedRegionsR);
            HOperatorSet.GenEmptyObj(out ho_ConnectedRegionsG);
            HOperatorSet.GenEmptyObj(out ho_ConnectedFilledRegion);
            HOperatorSet.GenEmptyObj(out ho_SelectedRegionsR);
            HOperatorSet.GenEmptyObj(out ho_SelectedRegionsG);
            HOperatorSet.GenEmptyObj(out ho_RegionDilationR);
            HOperatorSet.GenEmptyObj(out ho_RegionUnionR);
            HOperatorSet.GenEmptyObj(out ho_RegionDilationG);
            HOperatorSet.GenEmptyObj(out ho_RegionUnionG);
            HOperatorSet.GenEmptyObj(out RegionTemplateR);
            HOperatorSet.GenEmptyObj(out RegionTemplateG);
            HOperatorSet.GenEmptyObj(out ho_RegionDilation);
            HOperatorSet.GenEmptyObj(out ho_RegionUnion);
            HOperatorSet.GenEmptyObj(out ho_RegionUnion1);
            HOperatorSet.GenEmptyObj(out ho_RegionErosion);
            HOperatorSet.GenEmptyObj(out ho_RegionFillUp);
            HOperatorSet.GenEmptyObj(out selectedCoreRegionsFinal_HAL);

            //-----------------------------------------------------------------------
            //Hintergrundbereich aus dem Zellbild selektieren, damit dieser nach Berechnung der Zellkernregionen von diesen
            //subtrahiert werden kann, da nach der Zellkernregion-Berechnung die Regionen über den eigentlichen Zellrand hinaus
            //laufen können          
            //-----------------------------------------------------------------------
            HOperatorSet.Threshold(CellImg, out backgroundRegion, 0, 0);

            //-----------------------------------------------------------------------
            //RGB-Bild in 3 einkanalige Bilder zerlegen (r,g,b)
            //-----------------------------------------------------------------------
            ho_ImageR.Dispose();
            ho_ImageG.Dispose();
            ho_ImageB.Dispose();
            HOperatorSet.Decompose3(TargetImg, out ho_ImageR, out ho_ImageG, out ho_ImageB);
            //-----------------------------------------------------------------------
            //Farbklassen des Backprojection in Regionen umwandeln
            //-----------------------------------------------------------------------
            ho_RegionR.Dispose();
            HOperatorSet.Threshold(ho_ImageR, out ho_RegionR, 1, 255);
            ho_RegionG.Dispose();
            HOperatorSet.Threshold(ho_ImageG, out ho_RegionG, 1, 255);
            //-----------------------------------------------------------------------
            //Bereichsegmentierung
            //-----------------------------------------------------------------------
            ho_ConnectedRegionsR.Dispose();
            HOperatorSet.Connection(ho_RegionR, out ho_ConnectedRegionsR);
            ho_ConnectedRegionsG.Dispose();
            HOperatorSet.Connection(ho_RegionG, out ho_ConnectedRegionsG);
            //-----------------------------------------------------------------------
            //kleinere zusammenhängende Flächen ausschließen
            //-----------------------------------------------------------------------
            ho_SelectedRegionsR.Dispose();
            HOperatorSet.SelectShape(ho_ConnectedRegionsR, out ho_SelectedRegionsR, "area", "and", 10, 9999999);
            ho_SelectedRegionsG.Dispose();
            HOperatorSet.SelectShape(ho_ConnectedRegionsG, out ho_SelectedRegionsG, "area", "and", 10, 9999999);
            //-----------------------------------------------------------------------
            //Closing um nahe beieinanderliegende Regionen zu verbinden und kleinere Löcher zu schließen
            //-----------------------------------------------------------------------
            ho_RegionDilationR.Dispose();
            HOperatorSet.DilationCircle(ho_SelectedRegionsR, out ho_RegionDilationR, 2);
            ho_RegionUnionR.Dispose();
            HOperatorSet.Union1(ho_RegionDilationR, out ho_RegionUnionR);
            ho_RegionDilationG.Dispose();
            HOperatorSet.DilationCircle(ho_SelectedRegionsG, out ho_RegionDilationG, 2);
            ho_RegionUnionG.Dispose();
            HOperatorSet.Union1(ho_RegionDilationG, out ho_RegionUnionG);
            RegionTemplateR.Dispose();
            //HOperatorSet.ErosionCircle(ho_RegionUnionR, out RegionTemplateR, 2);
            HOperatorSet.ErosionCircle(ho_RegionUnionR, out RegionTemplateR, 2);
            RegionTemplateG.Dispose();
            //HOperatorSet.ErosionCircle(ho_RegionUnionG, out RegionTemplateG, 2);
            HOperatorSet.ErosionCircle(ho_RegionUnionG, out RegionTemplateG, 2);
            ho_RegionUnion.Dispose();
            HOperatorSet.Union2(RegionTemplateR, RegionTemplateG, out ho_RegionUnion);
            ho_RegionDilation.Dispose();
            HOperatorSet.DilationCircle(ho_RegionUnion, out ho_RegionDilation, 1);
            ho_RegionUnion1.Dispose();
            HOperatorSet.Union1(ho_RegionDilation, out ho_RegionUnion1);
            ho_RegionErosion.Dispose();
            HOperatorSet.ErosionCircle(ho_RegionUnion1, out ho_RegionErosion, 1);
            //-----------------------------------------------------------------------
            //Eingeschlossene Löcher schließen
            //-----------------------------------------------------------------------
            ho_RegionFillUp.Dispose();
            HOperatorSet.FillUp(ho_RegionErosion, out ho_RegionFillUp);
            ho_ConnectedFilledRegion.Dispose();
            HOperatorSet.Connection(ho_RegionFillUp, out ho_ConnectedFilledRegion);

            HOperatorSet.SelectShape(ho_ConnectedFilledRegion, out selectedCoreRegions_HAL, "area", "and", minCoreArea, 9999999);
            HOperatorSet.Difference(selectedCoreRegions_HAL, backgroundRegion, out selectedCoreRegionsFinal_HAL);

            //HOperatorSet.SetColor(window, "cyan");
            //HOperatorSet.DispObj(selectedCoreRegions_HAL, window);
            //MessageBox.Show("kerne");

            for (int i = 0; i < selectedCoreRegionsFinal_HAL.CountObj(); i++)
            {
                HOperatorSet.SelectObj(selectedCoreRegionsFinal_HAL, out selectedCore, i + 1);
                cellCoreData newCellCore = new cellCoreData();
                newCellCore.cellCore = selectedCore;
                selectedCoreRegions_internal.Add(newCellCore);
            }
            selectedCoreRegions = selectedCoreRegions_internal;
        }
        public static void OpeningCoreRegions(List<cellCoreData> CoreRegions, List<cellData> cells, int minCoreArea, out List<cellCoreData> selectedCoreRegions)
        {
            HTuple area, row, col;
            HObject regionErosion, regionDilation, connectedRegion, selectedCoreRegions_HAL, selectedCore;
            List<cellCoreData> List_internal = new List<cellCoreData>();

            for (int i = 0; i < CoreRegions.Count; i++)
            {
                HOperatorSet.ErosionCircle(CoreRegions[i].cellCore, out regionErosion, 2.5);
                HOperatorSet.Connection(regionErosion, out connectedRegion);
                HOperatorSet.DilationCircle(connectedRegion, out regionDilation, 2.5);
                HOperatorSet.SelectShape(regionDilation, out selectedCoreRegions_HAL, "area", "and", minCoreArea, 9999999);
                //Wenn mehrere Regionen entstanden sind, einzeln in die Liste speichern
                for (int j = 0; j < selectedCoreRegions_HAL.CountObj(); j++)
                {
                    HOperatorSet.SelectObj(selectedCoreRegions_HAL, out selectedCore, j + 1);
                    cellCoreData newCore = new cellCoreData();
                    newCore.cellCore = selectedCore;
                    //Schwerpunkt berechnen
                    HOperatorSet.AreaCenter(selectedCore, out area, out row, out col);

                    newCore.SP.X = col;
                    newCore.SP.Y = row;

                    List_internal.Add(newCore);
                }
            }
            selectedCoreRegions = List_internal;
        }

        /// <summary>
        /// Gibt den Zellbereich zurück, in dem der übergebene Kernbereich vorhanden ist. Ein Kernbereich kann mehrere verschiedene Zellbereiche schneiden. Deshalb den Zellbereich auswählen, wo
        //die meiste Kernfläche enthalten ist. Wurde keine Zelle ermittelt in der der Kern liegt
        /// wird null zurückgegeben
        /// </summary>
        /// <param name="cells"></param>
        /// <param name="core"></param>
        /// <returns></returns>
        public static cellData getCoreCell(List<cellData> cells, cellCoreData core)
        {
            HTuple area, row, column;
            HObject regionIntersection;

            List<int> indexListe = new List<int>();

            for (int i = 0; i < cells.Count; i++)
            {
                HOperatorSet.Intersection(cells[i].cellRegion, core.cellCore, out regionIntersection);
                HOperatorSet.AreaCenter(regionIntersection, out area, out row, out column);
                if (area != null)
                {
                    if (area.I > 0)
                    {
                        indexListe.Add(i);
                    }
                }
            }
            //Die Zelle ermitteln, die die meiste Kernfläche beinhaltet
            int maxArea = 0;
            int index = -1;
            for (int i = 0; i < indexListe.Count; i++)
            {
                HOperatorSet.Intersection(cells[indexListe[i]].cellRegion, core.cellCore, out regionIntersection);
                HOperatorSet.AreaCenter(regionIntersection, out area, out row, out column);
                if (area.I > maxArea)
                {
                    maxArea = area.I;
                    index = i;
                }
            }
            if (index > -1)
            {
                return cells[indexListe[index]];
            }
            else
                return null;
        }

        public static List<cellCoreData> DeleteInvalidCoreAreas(List<cellData> cells, List<cellCoreData> selectedCoresOpened)
        {
            HTuple areaIntersecRegion, rowIntersecRegion, colIntersecRegion, areaCore, rowCore, colCore;
            HObject regionIntersection, coreRegionOutOfCell, newCoreRegion;
            cellData cell;

            for (int i = 0; i < selectedCoresOpened.Count; i++)
            {
                //Ermitteln in welchem Zellbereich der aktuelleKernbereich liegt. Liegt der Kern in keinem Zellbereich -> ignorieren
                //Beachten dass ein Kernbereich mehrere verschiedene Zellbereiche schneiden kann. Deshalb den Zellbereich auswählen, wo
                //die meiste Kernfläche enthalten ist
                cell = getCoreCell(cells, selectedCoresOpened[i]);
                if (cell != null)
                {
                    HOperatorSet.Intersection(cell.cellRegion, selectedCoresOpened[i].cellCore, out regionIntersection);
                    HOperatorSet.AreaCenter(selectedCoresOpened[i].cellCore, out areaCore, out rowCore, out colCore);
                    HOperatorSet.AreaCenter(regionIntersection, out areaIntersecRegion, out rowIntersecRegion, out colIntersecRegion);
                    if (areaCore.I > areaIntersecRegion.I)
                    {
                        HOperatorSet.Difference(selectedCoresOpened[i].cellCore, regionIntersection, out coreRegionOutOfCell);
                        HOperatorSet.Difference(selectedCoresOpened[i].cellCore, coreRegionOutOfCell, out newCoreRegion);
                        selectedCoresOpened[i].cellCore = newCoreRegion;
                    }
                }
            }
            return selectedCoresOpened;
        }

        public static void checkCoresSP(List<cellCoreData> cellCores, List<cellData> cells, out List<cellCoreData> checkedCellCores, HWindow window)
        {
            HTuple row, col, area1, row1, col1, radius, isInside;
            HObject regionIntersection;
            bool spInsideCellRegion = false;
            HObject currentCell;
            HOperatorSet.GenEmptyObj(out currentCell);
            checkedCellCores = cellCores;
            //Prüfen ob der Schwerpunkt innerhalb der Zellregion liegt. Wenn nicht, dann
            //größten möglichen Innenkreis in den Kern legen und Mittelpunkt als Ker
            //mittelpunkt annehmen
            //HOperatorSet.ClearWindow(window);
            for (int i = 0; i < cellCores.Count; i++)
            {
                //HOperatorSet.SetColor(window, "white");
                //HOperatorSet.DispObj(cellCores[i].cellCore, window);
                //MessageBox.Show("core "+Convert.ToString(i));
                spInsideCellRegion = false;
                for (int k = 0; k < cells.Count; k++)
                {
                    //Korrekte Zellregion raussuchen
                    HOperatorSet.Intersection(cellCores[i].cellCore, cells[k].cellRegion, out regionIntersection);
                    HOperatorSet.AreaCenter(regionIntersection, out area1, out row1, out col1);
                    if (area1 > 0)
                    {
                        currentCell = cells[k].cellRegion;
                        //Prüfen ob SP des Kerns auch innerhalb der Zellregion liegt 
                        HOperatorSet.TestRegionPoint(cells[k].cellRegion, cellCores[i].SP.Y, cellCores[i].SP.X, out isInside);
                        if (isInside.I == 1)
                        {
                            spInsideCellRegion = true;
                            break;
                        }
                    }
                }
                //Liegt der Sp des aktuellen Zellkerns nicht in der Zellregion, den Mittelpunkt 
                //als SP festlegen
                if (spInsideCellRegion == false)
                {
                    HOperatorSet.InnerCircle(cellCores[i].cellCore, out row, out col, out radius);
                    cellCoreData newCellCore = new cellCoreData();
                    newCellCore.cellCore = cellCores[i].cellCore;
                    newCellCore.SP.X = col;
                    newCellCore.SP.Y = row;
                    newCellCore.isDarkCore = cellCores[i].isDarkCore;
                    checkedCellCores.RemoveAt(i);
                    checkedCellCores.Insert(i, newCellCore);
                }
            }
        }

        public static void assignCoresToCells(List<cellCoreData> Cores, List<cellData> cells, out List<cellData> cellsAssignedCores)
        {
            HObject regionIntersection;
            HTuple area, row, col;

            List<cellData> cellsAssignedCores_internal = cells;

            for (int i = 0; i < cells.Count; i++)
            {
                for (int j = 0; j < Cores.Count; j++)
                {
                    //Prüfen ob ein Kern innerhalb der aktuellen Zelle liegt
                    HOperatorSet.Intersection(cells[i].cellRegion, Cores[j].cellCore, out regionIntersection);
                    HOperatorSet.AreaCenter(regionIntersection, out area, out row, out col);

                    if (area.I > 0)
                    {
                        cellsAssignedCores_internal[i].CoreInfo.Add(Cores[j]);
                    }
                }
            }
            cellsAssignedCores = cellsAssignedCores_internal;
        }

        //Prüfen ob die beiden Kerne eine gemeinsame Schnittmenge haben. Wenn ja, dann die gemeinsame Schnitt
        //menge von den Kernregionen subtrahieren
        public static void checkCoresIntersectionRegion(List<cellCoreData> inputcellCores, out List<cellCoreData> cellCores)
        {
            HTuple row, col, area;
            HObject regionIntersection, newcellCoreRegion1, newcellCoreRegion2, regionDilation;
            cellCoreData cellCore1 = new cellCoreData();
            cellCoreData cellCore2 = new cellCoreData();

            cellCores = inputcellCores;

            for (int i = 0; i < inputcellCores.Count - 1; i++)
            {
                for (int j = i + 1; j < inputcellCores.Count; j++)
                {
                    HOperatorSet.Intersection(inputcellCores[i].cellCore, inputcellCores[j].cellCore, out regionIntersection);
                    HOperatorSet.AreaCenter(regionIntersection, out area, out row, out col);
                    if (area.I > 0)
                    {
                        HOperatorSet.DilationCircle(regionIntersection, out regionDilation, 1.5);
                        HOperatorSet.Difference(inputcellCores[i].cellCore, regionDilation, out newcellCoreRegion1);
                        HOperatorSet.Difference(inputcellCores[j].cellCore, regionDilation, out newcellCoreRegion2);

                        cellCore1.cellCore = newcellCoreRegion1;
                        cellCore2.cellCore = newcellCoreRegion2;
                        cellCore1.SP.X = inputcellCores[i].SP.X;
                        cellCore1.SP.Y = inputcellCores[i].SP.Y;
                        cellCore2.SP.X = inputcellCores[j].SP.X;
                        cellCore2.SP.Y = inputcellCores[j].SP.Y;
                        cellCore1.isDarkCore = inputcellCores[i].isDarkCore;
                        cellCore2.isDarkCore = inputcellCores[j].isDarkCore;
                        inputcellCores.RemoveAt(i);
                        inputcellCores.Insert(i, cellCore1);
                        inputcellCores.RemoveAt(j);
                        inputcellCores.Insert(j, cellCore2);
                    }
                }
            }
        }
        /*
        public static void calculateCoreGravityPoints(List<cellData> cells, List<cellData> calculatedCells)
        {
            HTuple area, row, col;

            for (int i = 0; i < cells.Count; i++)
            {
                for (int j = 0; j < cells[i].CoreInfo.Count; j++)
                {
                
                    HOperatorSet.AreaCenter(cells[i].CoreInfo[j].cellCore, out area, out row, out col);
                    pt.X = col;
                    pt.Y = row;
                
                }
            }
        }
        */
    }
    public static class ClusterClassification
    {
        public static void checkSingleCellsCores(List<cellData> inputcells, out List<cellData> cells)
        {
            for (int i = 0; i < inputcells.Count; i++)
            {
                //Für alle Einzelzellen
                if (inputcells[i].isCluster == false)
                {
                    //Prüfen, ob sie mehr als 2 Kerne beinhalten
                    if (inputcells[i].CoreInfo.Count > 2)
                    {
                        //Status auf Cluster setzen
                        inputcells[i].isCluster = true;
                        //cellData newCell = new cellData();
                        //newCell.cellRegion = inputcells[i].cellRegion;
                        //newCell.CoreInfo = inputcells[i].CoreInfo;
                        //newCell.isCluster = true;
                        //inputcells.RemoveAt(i);
                        //inputcells.Insert(i, newCell);
                    }
                }
            }
            cells = inputcells;
        }
        public static void iterativeErosionClassifier(HObject segmentedCellRegions, out List<cellData> cells, HWindow window)
        {
            int cellCount = 0;
            int maxIteration = 25;
            int currentIteration = 0;
            int radius = 2;
            int result = -1;

            HObject selectedObj, selectedObjDuplicate;
            List<cellData> cells_internal = new List<cellData>();

            for (int i = 0; i < segmentedCellRegions.CountObj(); i++)
            {
                currentIteration = 0;
                HOperatorSet.SelectObj(segmentedCellRegions, out selectedObj, i + 1);
                selectedObjDuplicate = selectedObj.CopyObj(1, 1);
                while (currentIteration < maxIteration)
                {
                    currentIteration++;
                    erode(selectedObj, radius, out selectedObj, out result);
                    if (result == 1)
                    {
                        erode(selectedObj, radius, out selectedObj, out result);
                        currentIteration++;
                    }
                    if (result == 2)
                    {
                        cellCount++;
                        cellData cellCluster = new cellData();
                        cellCluster.cellRegion = selectedObjDuplicate;
                        List<cellCoreData> list = new List<cellCoreData>();
                        cellCluster.CoreInfo = list;
                        cellCluster.isCluster = true;
                        cellCluster.nr = cellCount;
                        cells_internal.Add(cellCluster);
                        break;
                    }
                    if (result == 0)
                    {
                        cellCount++;
                        cellData cell = new cellData();
                        cell.cellRegion = selectedObjDuplicate;
                        List<cellCoreData> list = new List<cellCoreData>();
                        cell.CoreInfo = list;
                        cell.isCluster = false;
                        cell.nr = cellCount;
                        cells_internal.Add(cell);
                        break;
                    }
                }
                if ((currentIteration >= maxIteration) && result == 1)
                {
                    cellCount++;
                    cellData cell = new cellData();
                    cell.cellRegion = selectedObjDuplicate;
                    List<cellCoreData> list = new List<cellCoreData>();
                    cell.CoreInfo = list;
                    cell.isCluster = false;
                    cell.nr = cellCount;
                    cells_internal.Add(cell);
                }
            }
            cells = cells_internal;
        }
        public static void iterativeErosionClassifier(HObject segmentedCellRegions, out List<cellData> cells)
        {
            int cellCount = 0;
            int maxIteration = 25;
            int currentIteration = 0;
            int radius = 2;
            int result = -1;

            HObject selectedObj, selectedObjDuplicate;
            List<cellData> cells_internal = new List<cellData>();

            for (int i = 0; i < segmentedCellRegions.CountObj(); i++)
            {
                currentIteration = 0;
                HOperatorSet.SelectObj(segmentedCellRegions, out selectedObj, i + 1);
                selectedObjDuplicate = selectedObj.CopyObj(1, 1);
                while (currentIteration < maxIteration)
                {
                    currentIteration++;
                    erode(selectedObj, radius, out selectedObj, out result);
                    if (result == 1)
                    {
                        erode(selectedObj, radius, out selectedObj, out result);
                        currentIteration++;
                    }
                    if (result == 2)
                    {
                        cellCount++;
                        cellData cellCluster = new cellData();
                        cellCluster.cellRegion = selectedObjDuplicate;
                        List<cellCoreData> list = new List<cellCoreData>();
                        cellCluster.CoreInfo = list;
                        cellCluster.isCluster = true;
                        cellCluster.nr = cellCount;
                        cells_internal.Add(cellCluster);
                        break;
                    }
                    if (result == 0)
                    {
                        cellCount++;
                        cellData cell = new cellData();
                        cell.cellRegion = selectedObjDuplicate;
                        List<cellCoreData> list = new List<cellCoreData>();
                        cell.CoreInfo = list;
                        cell.isCluster = false;
                        cell.nr = cellCount;
                        cells_internal.Add(cell);
                        break;
                    }
                }
                if ((currentIteration >= maxIteration) && result == 1)
                {
                    cellCount++;
                    cellData cell = new cellData();
                    cell.cellRegion = selectedObjDuplicate;
                    List<cellCoreData> list = new List<cellCoreData>();
                    cell.CoreInfo = list;
                    cell.isCluster = false;
                    cell.nr = cellCount;
                    cells_internal.Add(cell);
                }
            }
            cells = cells_internal;
        }
        public static void iterativeErosionClassifier(List<cellData> inputCells, out List<cellData> cells)
        {
            int cellCount = 0;
            int maxIteration = 25;
            int currentIteration = 0;
            int radius = 2;
            int result = -1;

            HObject selectedObj, selectedObjDuplicate;
            List<cellData> cells_internal = new List<cellData>();

            for (int i = 0; i < inputCells.Count; i++)
            {
                currentIteration = 0;
                //HOperatorSet.SelectObj(segmentedCellRegions, out selectedObj, i + 1);
                selectedObj = inputCells[i].cellRegion;
                selectedObjDuplicate = selectedObj.CopyObj(1, 1);
                while (currentIteration < maxIteration)
                {
                    currentIteration++;
                    erode(selectedObj, radius, out selectedObj, out result);
                    if (result == 1)
                    {
                        erode(selectedObj, radius, out selectedObj, out result);
                        currentIteration++;
                    }
                    if (result == 2)
                    {
                        cellCount++;
                        cellData cellCluster = new cellData();
                        cellCluster.cellRegion = selectedObjDuplicate;
                        List<cellCoreData> list = new List<cellCoreData>();
                        cellCluster.CoreInfo = list;
                        cellCluster.isCluster = true;
                        cellCluster.nr = cellCount;
                        cellCluster.wasBarbelCell = inputCells[i].wasBarbelCell;
                        cells_internal.Add(cellCluster);
                        break;
                    }
                    if (result == 0)
                    {
                        cellCount++;
                        cellData cell = new cellData();
                        cell.cellRegion = selectedObjDuplicate;
                        List<cellCoreData> list = new List<cellCoreData>();
                        cell.CoreInfo = list;
                        cell.isCluster = false;
                        cell.nr = cellCount;
                        cell.wasBarbelCell = inputCells[i].wasBarbelCell;
                        cells_internal.Add(cell);
                        break;
                    }
                }
                if ((currentIteration >= maxIteration) && result == 1)
                {
                    cellCount++;
                    cellData cell = new cellData();
                    cell.cellRegion = selectedObjDuplicate;
                    List<cellCoreData> list = new List<cellCoreData>();
                    cell.CoreInfo = list;
                    cell.isCluster = false;
                    cell.nr = cellCount;
                    cell.wasBarbelCell = inputCells[i].wasBarbelCell;
                    cells_internal.Add(cell);
                }
            }
            cells = cells_internal;
        }
        private static void erode(HObject region, int radius, out HObject regionEroded, out int result)
        {
            int objCount;
            HObject connectedRegion, selectedRegions;

            HOperatorSet.ErosionCircle(region, out regionEroded, radius);
            HOperatorSet.Connection(regionEroded, out connectedRegion);
            HOperatorSet.SelectShape(connectedRegion, out selectedRegions, "area", "and", 250, 99999999);
            objCount = selectedRegions.CountObj();
            result = -1;
            if (objCount == 1)
                result = 1;
            if (objCount > 1)
                result = 2;
            if (objCount == 0)
                result = 0;
        }
    }
    public class cellSeparation
    {
        public struct line
        {
            public double x1;
            public double y1;
            public double x2;
            public double y2;
        };
        public bool doContextDilation = false;
        private FindSpecialContourPoint m_dcpFinder;
        private Algorithms.PathFinder m_pfinder;
        private byte[,] m_cellField;
        private cellData m_cell;
        private List<cellCoreData> allCoresInCell = new List<cellCoreData>();
        private List<cellData> m_separatedCells = new List<cellData>();
        private List<HObject> m_separationLinesList = new List<HObject>();
        public List<line> m_invalidCorePairs = new List<line>();
        private HTuple rowOL, colOL, rowUR, colUR;
        private HObject m_restCellRegion;
        private HObject m_currentCellRegion;
        private HWindow m_HalWindow;
        public bool isolationFailed = false;
        public HObject nonSeparatedRegions;
        public cellSeparation(cellData inputCell, int DCP_AnzEbenen, bool cellGrowthSim)
        {
            m_cell = inputCell;
            //Feld erstellen für Berechnung des kürzesten Weges innerhalb einer
            //Zelle zw. den Zellkernen
            m_cellField = getByteFieldFromCellCluster(m_cell.cellRegion);
            //Der Rest der Zellfläche des Clusters nach Zelltrennungen ist am Anfang
            //natürlich genau die Zellfläche selbst, weil bisher keine Trennung erfolgt ist
            m_restCellRegion = m_cell.cellRegion;
            m_currentCellRegion = m_cell.cellRegion;
            for (int i = 0; i < inputCell.CoreInfo.Count; i++)
            {
                allCoresInCell.Add(inputCell.CoreInfo[i]);
            }
            //m_dcpFinder = new FindSpecialContourPoint(m_cell.cellRegion, 5);
            if (cellGrowthSim == false)
            {
                doContextDilation = false;
                //Hier die Zellregion genauso dilatieren wie bei der Erstellung der Pfadmap in der Methode "getByteFieldFromCellCluster"
                //damit die DCPs auch wirklich auf der Kontur liegen. Würde man hier nicht dilatieren kann der Pfad an der Kontur "hinter" dem
                //DCP herlaufen und eine Trennung an der Stelle wird unmöglich, da beide DCPs mathematisch auf der gleichen Seite des Pfades
                //liegen würden
                HObject regionDilation;
                HOperatorSet.DilationCircle(m_cell.cellRegion, out regionDilation, 0.5);
                //m_dcpFinder = new FindSpecialContourPoint(m_cell.cellRegion, DCP_AnzEbenen);
                m_dcpFinder = new FindSpecialContourPoint(regionDilation, DCP_AnzEbenen);
                ActivatePathFinder();
            }
            else
                doContextDilation = true;
        }
        public cellSeparation(cellData inputCell, int DCP_AnzEbenen, bool cellGrowthSim, HWindow window)
        {
            m_cell = inputCell;
            //Feld erstellen für Berechnung des kürzesten Weges innerhalb einer
            //Zelle zw. den Zellkernen
            m_cellField = getByteFieldFromCellCluster(m_cell.cellRegion);
            //Der Rest der Zellfläche des Clusters nach Zelltrennungen ist am Anfang
            //natürlich genau die Zellfläche selbst, weil bisher keine Trennung erfolgt ist
            m_restCellRegion = m_cell.cellRegion;
            m_currentCellRegion = m_cell.cellRegion;
            m_HalWindow = window;
            for (int i = 0; i < inputCell.CoreInfo.Count; i++)
            {
                allCoresInCell.Add(inputCell.CoreInfo[i]);
            }

            if (cellGrowthSim == false)
            {
                //m_dcpFinder = new FindSpecialContourPoint(window, m_cell.cellRegion, 5);
                doContextDilation = false;
                HObject regionDilation;
                HOperatorSet.DilationCircle(m_cell.cellRegion, out regionDilation, 0.5);
                //m_dcpFinder = new FindSpecialContourPoint(window, m_cell.cellRegion, DCP_AnzEbenen);
                m_dcpFinder = new FindSpecialContourPoint(window, regionDilation, DCP_AnzEbenen);

                ActivatePathFinder();
            }
            else
                doContextDilation = true;
        }
        //Zelltrennung innerhalb des Clusters mit Hilfe der kontextbasierten Dilatation. Es wird quasi das Zellwachstum ausgehend
        //von den Zellkernen simuliert und an den Berührungspunkten verschiedener Zellen das Wachstum jeweils an der entspr.Stelle gestoppt.
        public void seperateCellsWithContextDilation(int imgWidth, int imgHeight, HWindow window)
        {
            //Zellkernwachstum simulieren
            WarpBitmap resImg = simulateCellGrowth(imgWidth, imgHeight, window);
            resImg.Image.Save(Application.StartupPath + "\\contextDilationResult.bmp", System.Drawing.Imaging.ImageFormat.Bmp);
            //Aus dem Ergebnisbild Zellregionen erzeugen
            createCellRegionsFromcontextDilationImage(resImg, window);
        }
        public void seperateCellsWithContextDilation(int imgWidth, int imgHeight)
        {
            //Zellkernwachstum simulieren
            WarpBitmap resImg = simulateCellGrowth(imgWidth, imgHeight);
            resImg.Image.Save(Application.StartupPath + "\\contextDilationResult.bmp", System.Drawing.Imaging.ImageFormat.Bmp);
            //Aus dem Ergebnisbild Zellregionen erzeugen
            createCellRegionsFromcontextDilationImage(resImg);
        }
        public void createCellRegionsFromcontextDilationImage(WarpBitmap contextDilationImg, HWindow window)
        {
            HTuple area, row, col;
            HObject region;
            List<HObject> cellRegions = new List<HObject>();
            //In Halconregion umwandeln
            try
            {
                //HObject contextDilationImg_HAL = cellSegmentation_Threshold.BitmapToHObject(new Bitmap((Bitmap)contextDilationImg.Image.Clone()));
                HObject contextDilationImg_HAL, connectedRegions, selectedRegions, selectedRegion;
                HOperatorSet.ReadImage(out contextDilationImg_HAL, Application.StartupPath + "\\contextDilationResult.bmp");
                //HOperatorSet.SetSystem("neighborhood", 8);
                for (int i = 1; i < 255; i++)
                {
                    HOperatorSet.Threshold(contextDilationImg_HAL, out region, i, i);
                    HOperatorSet.Connection(region, out connectedRegions);
                    HOperatorSet.SelectShape(connectedRegions, out selectedRegions, "area", "and", 100, 999999999);
                    //Nur wenn eine Region mit dem aktuellen Schwellwert existiert wird diese in die Zellliste gespeichert
                    HOperatorSet.AreaCenter(selectedRegions, out area, out row, out col);
                    double max = 0;
                    int index = 0;
                    for (int j = 0; j < area.Length; j++)
                    {
                        if (area[j].D > max)
                        {
                            max = area[j].D;
                            index = j;
                        }
                    }
                    //Falls keine Region vorhanden ist kann auch nicht auf ein Flächenelement zugegriffen werden
                    if (area.Length > 0)
                    {
                        if (area[index].D > 100)
                        {
                            HOperatorSet.SelectObj(selectedRegions, out selectedRegion, index + 1);
                            cellRegions.Add(selectedRegion);
                            //Neue Zell erstellen
                            cellData newCell = new cellData();
                            newCell.cellRegion = selectedRegion;
                            //Zellkerne zuweisen....
                            List<cellCoreData> cellCores;
                            cellCores = getCoresInSubRegion(selectedRegion, allCoresInCell);
                            newCell.CoreInfo = cellCores;
                            m_separatedCells.Add(newCell);
                        }
                    }
                    else
                        break;
                }
                //HOperatorSet.SetSystem("neighborhood", 4);
            }
            catch (System.Exception ex)
            {
                MessageBox.Show("Fehler in Funktion 'createCellRegionsFromcontextDilationImage' " + ex.Message);
            }
        }
        public void createCellRegionsFromcontextDilationImage(WarpBitmap contextDilationImg)
        {
            HTuple area, row, col;
            HObject region;
            List<HObject> cellRegions = new List<HObject>();
            //In Halconregion umwandeln
            try
            {
                //HObject contextDilationImg_HAL = cellSegmentation_Threshold.BitmapToHObject(new Bitmap((Bitmap)contextDilationImg.Image.Clone()));
                HObject contextDilationImg_HAL, connectedRegions, selectedRegions, selectedRegion;
                HOperatorSet.ReadImage(out contextDilationImg_HAL, Application.StartupPath + "\\contextDilationResult.bmp");
                //HOperatorSet.SetSystem("neighborhood", 8);
                for (int i = 1; i < 255; i++)
                {
                    HOperatorSet.Threshold(contextDilationImg_HAL, out region, i, i);
                    HOperatorSet.Connection(region, out connectedRegions);
                    HOperatorSet.SelectShape(connectedRegions, out selectedRegions, "area", "and", 100, 999999999);
                    //Nur wenn eine Region mit dem aktuellen Schwellwert existiert wird diese in die Zellliste gespeichert
                    HOperatorSet.AreaCenter(selectedRegions, out area, out row, out col);
                    double max = 0;
                    int index = 0;
                    for (int j = 0; j < area.Length; j++)
                    {
                        if (area[j].D > max)
                        {
                            max = area[j].D;
                            index = j;
                        }
                    }
                    //Falls keine Region vorhanden ist kann auch nicht auf ein Flächenelement zugegriffen werden
                    if (area.Length > 0)
                    {
                        if (area[index].D > 100)
                        {
                            HOperatorSet.SelectObj(selectedRegions, out selectedRegion, index + 1);
                            cellRegions.Add(selectedRegion);
                            //Neue Zell erstellen
                            cellData newCell = new cellData();
                            newCell.cellRegion = selectedRegion;
                            //Zellkerne zuweisen....
                            List<cellCoreData> cellCores;
                            cellCores = getCoresInSubRegion(selectedRegion, allCoresInCell);
                            newCell.CoreInfo = cellCores;
                            m_separatedCells.Add(newCell);
                        }
                    }
                }
                //HOperatorSet.SetSystem("neighborhood", 4);
            }
            catch (System.Exception ex)
            {
                MessageBox.Show("Fehler in Funktion 'createCellRegionsFromcontextDilationImage' " + ex.Message);
            }
        }

        public WarpBitmap simulateCellGrowth(int imgWidth, int imgHeight, HWindow window)
        {
            HTuple rows, cols;
            HTuple x, y, x2, y2;
            int a, b;
            bool dilated = true;
            bool hit = false;

            TPoint[,] source = new TPoint[imgWidth, imgHeight];
            TPoint[,] target = new TPoint[imgWidth, imgHeight];

            for (int i = 0; i < imgHeight; i++)
            {
                for (int j = 0; j < imgWidth; j++)
                {
                    TPoint point = new TPoint(j, i, 0);
                    TPoint point2 = new TPoint(j, i, 0);
                    source[j, i] = point;
                    target[j, i] = point2;
                }
            }

            //Zellkernregionen in Quelldatensatz labeln
            for (int i = 0; i < allCoresInCell.Count; i++)
            {
                HOperatorSet.GetRegionContour(allCoresInCell[i].cellCore, out rows, out cols);
                for (int j = 0; j < rows.Length; j++)
                {
                    source[cols[j].I, rows[j].I].Label = i + 1;
                    //target[cols[j].I, rows[j].I].Label = i + 1;
                }
            }
            //Clusterkonturpunkte in Quelldatensatz markieren
            HOperatorSet.GetRegionContour(m_cell.cellRegion, out rows, out cols);
            for (int i = 0; i < rows.Length; i++)
            {
                source[cols[i].I, rows[i].I].Label = -1;
                target[cols[i].I, rows[i].I].Label = -1;
            }
            //Zelllochkonturen in Quelldatensatz markieren, falls vorhanden
            if (m_cell.cellHoles != null)
            {
                for (int i = 0; i < m_cell.cellHoles.Length; i++)
                {
                    HOperatorSet.GetRegionContour(m_cell.cellHoles[i], out rows, out cols);
                    for (int j = 0; j < rows.Length; j++)
                    {
                        source[cols[j].I, rows[j].I].Label = -1;
                        target[cols[j].I, rows[j].I].Label = -1;
                    }
                }
            }
            //Kleinstes umschließendes Rechteck der Clusterregion berechnen
            HOperatorSet.SmallestRectangle1(m_cell.cellRegion, out y, out x, out y2, out x2);
            a = y2.I - y.I;
            b = x2.I - x.I;

            //Solange den Dilatationsvorgang fortsetzen bis keine Dilatation mehr möglich ist
            //for(int m=0;m<30;m++)
            while (dilated == true)
            {
                dilated = false;
                for (int i = y.I + 1; i < y.I + a; i++)
                {
                    for (int j = x.I + 1; j < x.I + b; j++)
                    {
                        hit = false;
                        for (int k = -1; k <= 1; k++)
                        {
                            for (int l = -1; l <= 1; l++)
                            {
                                //Prüfen ob sich der aktuelle Pixel um eine Zellkernregion handelt
                                if (source[j + l, i + k].Label > 0)
                                {
                                    //Prüfen ob der Referenzpunkt bereits einer anderen Region oder der Clusterkontur zugeordnet ist
                                    if (((source[j, i].Label > 0) && (source[j, i].Label != source[j + l, i + k].Label)) || (source[j, i].Label == -1))
                                    {
                                        //Nichts machen
                                    }
                                    else if (source[j, i].Label == 0)
                                    {
                                        target[j, i].Label = source[j + l, i + k].Label;
                                        dilated = true;
                                        hit = true;
                                        break;
                                    }
                                }
                            }
                            if (hit == true)
                                break;
                        }
                    }
                }
                //Quelldatensatz aktualisieren für die nächste Dilatationsrunde
                DeepCopyer dc = new DeepCopyer();
                source = (TPoint[,])dc.copy(target);
            }
            //Neues Bild erstellen mit Grauwerten die den Labels der Regionen entsprechen, d.h. max 255 verschiedene Regionen möglich
            WarpBitmap targetImg = new SBBitmap.WarpBitmap(imgWidth, imgHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb);

            for (int i = 0; i < imgHeight; i++)
            {
                for (int j = 0; j < imgWidth; j++)
                {
                    if (target[j, i].Label == -1)
                        targetImg.SetPixel(j, i, Color.Red);
                    if (target[j, i].Label > 0)
                        targetImg.SetPixel(j, i, (byte)target[j, i].Label);
                }
            }
            return targetImg;
        }
        public WarpBitmap simulateCellGrowth(int imgWidth, int imgHeight)
        {
            HTuple rows, cols;
            HTuple x, y, x2, y2;
            int a, b;
            bool dilated = true;
            bool hit = false;

            TPoint[,] source = new TPoint[imgWidth, imgHeight];
            TPoint[,] target = new TPoint[imgWidth, imgHeight];

            for (int i = 0; i < imgHeight; i++)
            {
                for (int j = 0; j < imgWidth; j++)
                {
                    TPoint point = new TPoint(j, i, 0);
                    TPoint point2 = new TPoint(j, i, 0);
                    source[j, i] = point;
                    target[j, i] = point2;
                }
            }

            //Zellkernregionen in Quelldatensatz labeln
            for (int i = 0; i < allCoresInCell.Count; i++)
            {
                HOperatorSet.GetRegionContour(allCoresInCell[i].cellCore, out rows, out cols);
                for (int j = 0; j < rows.Length; j++)
                {
                    source[cols[j].I, rows[j].I].Label = i + 1;
                    //target[cols[j].I, rows[j].I].Label = i + 1;
                }
            }
            //Clusterkonturpunkte in Quelldatensatz markieren
            HOperatorSet.GetRegionContour(m_cell.cellRegion, out rows, out cols);
            for (int i = 0; i < rows.Length; i++)
            {
                source[cols[i].I, rows[i].I].Label = -1;
                target[cols[i].I, rows[i].I].Label = -1;
            }
            if (m_cell.cellHoles != null)
            {
                //Zelllochkonturen in Quelldatensatz markieren, falls vorhanden
                for (int i = 0; i < m_cell.cellHoles.Length; i++)
                {
                    HOperatorSet.GetRegionContour(m_cell.cellHoles[i], out rows, out cols);
                    for (int j = 0; j < rows.Length; j++)
                    {
                        source[cols[j].I, rows[j].I].Label = -1;
                        target[cols[j].I, rows[j].I].Label = -1;
                    }
                }
            }
            //Kleinstes umschließendes Rechteck der Clusterregion berechnen
            HOperatorSet.SmallestRectangle1(m_cell.cellRegion, out y, out x, out y2, out x2);
            a = y2.I - y.I;
            b = x2.I - x.I;

            //Solange den Dilatationsvorgang fortsetzen bis keine Dilatation mehr möglich ist
            //for(int m=0;m<30;m++)
            while (dilated == true)
            {
                dilated = false;
                for (int i = y.I + 1; i < y.I + a; i++)
                {
                    for (int j = x.I + 1; j < x.I + b; j++)
                    {
                        hit = false;
                        for (int k = -1; k <= 1; k++)
                        {
                            for (int l = -1; l <= 1; l++)
                            {
                                //Prüfen ob sich der aktuelle Pixel um eine Zellkernregion handelt
                                if (source[j + l, i + k].Label > 0)
                                {
                                    //Prüfen ob der Referenzpunkt bereits einer anderen Region oder der Clusterkontur zugeordnet ist
                                    if (((source[j, i].Label > 0) && (source[j, i].Label != source[j + l, i + k].Label)) || (source[j, i].Label == -1))
                                    {
                                        //Nichts machen
                                    }
                                    else if (source[j, i].Label == 0)
                                    {
                                        target[j, i].Label = source[j + l, i + k].Label;
                                        dilated = true;
                                        hit = true;
                                        break;
                                    }
                                }
                            }
                            if (hit == true)
                                break;
                        }
                    }
                }
                //Quelldatensatz aktualisieren für die nächste Dilatationsrunde
                DeepCopyer dc = new DeepCopyer();
                source = (TPoint[,])dc.copy(target);
            }
            //Neues Bild erstellen mit Grauwerten die den Labels der Regionen entsprechen, d.h. max 255 verschiedene Regionen möglich
            WarpBitmap targetImg = new SBBitmap.WarpBitmap(imgWidth, imgHeight, System.Drawing.Imaging.PixelFormat.Format24bppRgb);

            for (int i = 0; i < imgHeight; i++)
            {
                for (int j = 0; j < imgWidth; j++)
                {
                    if (target[j, i].Label == -1)
                        targetImg.SetPixel(j, i, Color.Red);
                    if (target[j, i].Label > 0)
                        targetImg.SetPixel(j, i, (byte)target[j, i].Label);
                }
            }
            return targetImg;
        }

        private void ActivatePathFinder()
        {
            //Objekt zum suchen des kürzesten Weges zw. 2 Punkten erstellen
            //A*-Algo Parameter Einstellungen
            m_pfinder = new Algorithms.PathFinder(m_cellField);
            m_pfinder.Diagonals = false;
            m_pfinder.Formula = Algorithms.HeuristicFormula.Manhattan;
            m_pfinder.HeuristicEstimate = 1;
            m_pfinder.SearchLimit = 500000;
            m_pfinder.DebugFoundPath = false;
        }

        public List<cellData> getseparatedCells()
        {
            return m_separatedCells;
        }

        List<DoublePoint> getPointsFromSeperationLines(HObject regionLine1, HObject regionLine2)
        {
            HTuple rows, cols, rows2, cols2;
            List<DoublePoint> points = new List<DoublePoint>();

            HOperatorSet.GetRegionPoints(regionLine1, out rows, out cols);
            HOperatorSet.GetRegionPoints(regionLine2, out rows2, out cols2);
            for (int i = 0; i < rows.Length; i++)
            {
                DoublePoint pt = new DoublePoint();
                pt.X = cols[i];
                pt.Y = rows[i];
                points.Add(pt);
            }
            for (int i = 0; i < rows2.Length; i++)
            {
                DoublePoint pt = new DoublePoint();
                pt.X = cols2[i];
                pt.Y = rows2[i];
                points.Add(pt);
            }
            return points;
        }

        byte[,] insertBarrierInPathField(byte[,] Field, List<DoublePoint> barrierPoints)
        {
            for (int i = 0; i < barrierPoints.Count; i++)
            {
                try
                {
                    if (barrierPoints[i].X - colOL.I >= Field.GetLength(0))
                        Field[(int)(Field.GetLength(0) - 1), (int)(barrierPoints[i].Y - rowOL.I)] = 0;
                    else if (barrierPoints[i].Y - rowOL.I >= Field.GetLength(1))
                        Field[(int)(barrierPoints[i].X - colOL.I), (int)(Field.GetLength(1) - 1)] = 0;
                    else
                        Field[(int)(barrierPoints[i].X - colOL.I), (int)(barrierPoints[i].Y - rowOL.I)] = 0;
                }
                catch (System.Exception ex)
                {
                    MessageBox.Show("Fehler beim Einfügen der Trennlinien in die Path-Map");
                }
            }
            return Field;
        }

        //Einzelzellen im Cluster separieren
        public void separateCellsInCluster(List<cellCoreData> cellCores, int DCP_AnzEbenen)
        {
            HObject resultRegion;
            HObject subRegion;
            HObject separationLine1;
            HObject separationLine2;
            Point corePt1 = new Point();
            Point corePt2 = new Point();

            if (cellCores.Count <= 1)
                return;
            List<int> indexListe = new List<int>();

            //Zellkern mit dem kleinsten x-Wert als Startkern setzen
            var sortedCoresX = from item in cellCores
                               orderby item.SP.X ascending
                               select item;


            corePt1.X = (int)sortedCoresX.ElementAt(0).SP.X;
            corePt1.Y = (int)sortedCoresX.ElementAt(0).SP.Y;

            corePt2 = searchNearestCore(corePt1, sortedCoresX, indexListe, m_invalidCorePairs);
            //Wenn kein gültiger Kern gefunden wurde, Funktion verlassen
            if ((corePt2.X == -1) && (corePt2.Y == -1))
                return;

            Point corePt1_delta = new Point();
            Point corePt2_delta = new Point();
            corePt1_delta.X = corePt1.X - colOL;
            corePt1_delta.Y = corePt1.Y - rowOL;
            corePt2_delta.X = corePt2.X - colOL;
            corePt2_delta.Y = corePt2.Y - rowOL;

            //Pfad zwischen den beiden Kernen berechnen
            List<PathFinderNode> nodes = m_pfinder.FindPath(corePt1_delta, corePt2_delta);

            while (cellCores.Count() > 0)
            {
                //Wenn corePt2 auf -1/-1 gesetzt wurde, weil es keinen gültigen Kernpartner von corePt1 mehr gibt
                //dann die while Schleife abbrechen
                if ((corePt2.X == -1) && (corePt2.Y == -1))
                    break;
                //Wenn nur ein Kern übrig ist braucht die Fkt. zur Trennung zwischen 2 Kernen nicht aufgerufen werden
                //und brechen die Schleife ab
                if (cellCores.Count() == 1)
                {
                    //MessageBox.Show("Nur ein Kern übrig...springe aus while-schleife");
                    isolationFailed = true;
                    break;
                }
                bool sepLinesGenerated = isolateCore(corePt1, corePt2, m_dcpFinder, DCP_AnzEbenen, nodes, m_cell, cellCores, out resultRegion, out separationLine1, out separationLine2);
                Application.DoEvents();
                if (sepLinesGenerated == false)
                {
                    //Die Zellkerntrennung soll weiterhin ausgeführt werden mit dem nächsten Zellkernpaar...
                    //D.h. die Koordinaten der aktuellen nicht trennbaren Kerne werden in eine Liste
                    //m_invalidCorePairs gespeichert und danach die Fkt. erneut aufgerufen. Es wird wieder der
                    //linkeste Kern bestimmt und der nächste Nachbar, unter Berücksichtigung der Liste mit den
                    //ungültigen Kernpaaren
                    line spPair = new line();
                    spPair.x1 = corePt1.X;
                    spPair.y1 = corePt1.Y;
                    spPair.x2 = corePt2.X;
                    spPair.y2 = corePt2.Y;
                    m_invalidCorePairs.Add(spPair);
                    isolationFailed = true;

                    separateCellsInCluster(cellCores, DCP_AnzEbenen);

                    break;
                }
                if ((separationLine1.CountObj() == 1) && (separationLine2.CountObj() == 1))
                {
                    //Trennlinien als Hindernisse in die Map einfügen
                    List<DoublePoint> separationLinesPoints = getPointsFromSeperationLines(separationLine1, separationLine2);
                    m_cellField = insertBarrierInPathField(m_cellField, separationLinesPoints);
                    ActivatePathFinder();
                }
                //Prüfen ob die Zellregion aufgetrennt wurde
                if (resultRegion.CountObj() > 1)
                {
                    //Abgetrennte SubClusterRegion ermitteln, in der sich auch Core2 befindet
                    subRegion = selectRegion(resultRegion, corePt2);
                    //Prüfen ob sich in der aufgetrennten Region, in der sich auch Core2 befindet, mehr als ein Kern befindet
                    List<cellCoreData> coresInSubRegion = getCoresInSubRegion(subRegion, cellCores);
                    if (coresInSubRegion.Count > 1)
                    {
                        //Aus der cellCores Liste alle Kerne löschen, die nun in der neuen Liste
                        //coresInSubRegion stehen. Damit wenn die rekursion wieder an die Stelle zurückkommt
                        //auch nur der/die übrig gebliebenen Kerne in der Liste stehen
                        for (int i = 0; i < coresInSubRegion.Count; i++)
                        {
                            for (int j = 0; j < cellCores.Count; j++)
                            {
                                if ((coresInSubRegion[i].SP.X == cellCores[j].SP.X) && (coresInSubRegion[i].SP.Y == cellCores[j].SP.Y))
                                {
                                    cellCores.RemoveAt(j);
                                    break;
                                }
                            }
                        }
                        m_currentCellRegion = subRegion;
                        //Zellen in Sub-Region trennen
                        separateCellsInCluster(coresInSubRegion, DCP_AnzEbenen);
                        //Wenn nur ein Kern in einer abgetrennten Region übrig blieb, dann
                        //aus der Liste entfernen und in die Liste der separierten Zellen hinzufügen
                        if (cellCores.Count == 1)
                        {
                            //Es handelt sich um eine abgetrennte Einzelzelle
                            cellData newCell = new cellData();
                            //newCell.cellRegion = cellCores[0].cellCore;
                            newCell.cellRegion = selectRegion(resultRegion, corePt1);
                            List<cellCoreData> cores = new List<cellCoreData>();
                            cores.Add(cellCores[0]);
                            newCell.CoreInfo = cores;
                            //Einzelzelle in globale Liste hinzufügen
                            m_separatedCells.Add(newCell);
                            //Zellkern aus Zellkernliste entfernen
                            cellCores.RemoveAt(0);
                        }
                        else if (cellCores.Count > 1)
                        {
                            //Fall 1: Es sind entweder noch mehrere Kerne in der Region in dieser Rekursionsebene enthalten
                            //Fall 2: Die Region in der sich CorePt1 befindet ist auch schon vom Rest des Clusters abgeschnitten, aber es sind noch Zellkerne
                            //        in einem anderen Teil des Clusters übrig -> Dann müssten corePt1 und corePt2 neu gesetzt werden!
                            //corePt1 bleibt erhalten, corePt2 neu bestimmen

                            //aktuell betrachtete Zellregion neu setzen
                            m_currentCellRegion = selectRegion(resultRegion, corePt1);

                            //wenn in der Region von corePt1 nur ein Kern vorhanden ist handelt es sich um Fall 2, sind > 1 Zellkerne vorhanden Fall 1!
                            List<cellCoreData> coresInSubRegion2 = getCoresInSubRegion(m_currentCellRegion, cellCores);
                            if (coresInSubRegion2.Count > 1)
                            {

                                var sortedCores2 = from item in cellCores
                                                   orderby item.SP.X ascending
                                                   select item;
                                corePt2 = searchNearestCore(corePt1, sortedCores2, indexListe, m_invalidCorePairs);
                                if ((corePt2.X == -1) && (corePt2.Y == -1))
                                    break;
                                corePt2_delta.X = corePt2.X - colOL;
                                corePt2_delta.Y = corePt2.Y - rowOL;

                                nodes.Clear();
                                nodes = m_pfinder.FindPath(corePt1_delta, corePt2_delta);
                                if (nodes != null)
                                {
                                    //
                                }
                                else
                                {
                                    //Probieren ob das klappt:
                                    line spPair = new line();
                                    spPair.x1 = corePt1.X;
                                    spPair.y1 = corePt1.Y;
                                    spPair.x2 = corePt2.X;
                                    spPair.y2 = corePt2.Y;
                                    m_invalidCorePairs.Add(spPair);
                                    isolationFailed = true;

                                    break;
                                }
                            }
                            //Fall 2 hier implementieren
                            else
                            {
                                //Es kann vorkommen, dass in einer vorherigen Rekursion bereits eine Einzelzelle mit dem
                                //hier gesetzten corePt1 generiert wurde. Deshalb zuerst prüfen, ob corePt1 noch in der cellCore
                                //Liste vorhanden ist. Wenn nicht, dann corePt1 und corePt2 ohne Erstellen einer neuen Zelle neu
                                //setzen
                                int index = getIndex(corePt1, cellCores);
                                if (index > -1)
                                {
                                    cellData newCell = new cellData();
                                    newCell.cellRegion = m_currentCellRegion;
                                    List<cellCoreData> cores = new List<cellCoreData>();
                                    cores.Add(getCoreByCoord(corePt1, coresInSubRegion2));
                                    newCell.CoreInfo = cores;
                                    //Einzelzelle in globale Liste hinzufügen
                                    m_separatedCells.Add(newCell);
                                    //Zellkern aus Zellkernliste entfernen
                                    cellCores.RemoveAt(getIndex(corePt1, cellCores));
                                }
                                //corePt1 und corePt2 neu setzen:
                                //Zellkern mit dem kleinsten x-Wert als Startkern setzen
                                sortedCoresX = from item in cellCores
                                               orderby item.SP.X ascending
                                               select item;


                                corePt1.X = (int)sortedCoresX.ElementAt(0).SP.X;
                                corePt1.Y = (int)sortedCoresX.ElementAt(0).SP.Y;

                                corePt2 = searchNearestCore(corePt1, sortedCoresX, indexListe, m_invalidCorePairs);
                                //Wenn kein gültiger Kern gefunden wurde, Funktion verlassen
                                if ((corePt2.X == -1) && (corePt2.Y == -1))
                                    return;

                                corePt1_delta.X = corePt1.X - colOL;
                                corePt1_delta.Y = corePt1.Y - rowOL;
                                corePt2_delta.X = corePt2.X - colOL;
                                corePt2_delta.Y = corePt2.Y - rowOL;

                                //aktuell betrachtete Zellregion neu setzen
                                //m_currentCellRegion = selectRegion(resultRegion, corePt1);
                                //Änderung 09.11.11-> Wenn beide Kerne neu gesetzt werden kann die resultRegion nicht mehr passen
                                //-> einfach die ganze Zellregion zuweisen
                                m_currentCellRegion = m_cell.cellRegion;

                                nodes.Clear();
                                nodes = m_pfinder.FindPath(corePt1_delta, corePt2_delta);
                                if ((nodes != null) && (nodes.Count != null))
                                {
                                    //
                                }
                                else
                                {
                                    //Probieren ob das klappt:
                                    line spPair = new line();
                                    spPair.x1 = corePt1.X;
                                    spPair.y1 = corePt1.Y;
                                    spPair.x2 = corePt2.X;
                                    spPair.y2 = corePt2.Y;
                                    m_invalidCorePairs.Add(spPair);
                                    isolationFailed = true;

                                    break;
                                }
                            }
                        }
                    }
                    else
                    {
                        //Es handelt sich um eine abgetrennte Einzelzelle
                        cellData newCell = new cellData();
                        newCell.cellRegion = subRegion;
                        List<cellCoreData> cores = new List<cellCoreData>();
                        cores.Add(getCoreByCoord(corePt2, coresInSubRegion));
                        newCell.CoreInfo = cores;
                        //Einzelzelle in globale Liste hinzufügen
                        m_separatedCells.Add(newCell);
                        //Zellkern aus Zellkernliste entfernen
                        cellCores.RemoveAt(getIndex(corePt2, cellCores));
                        //Prüfen ob corePt1 auch in einem getrennten Zellbereich liegt
                        subRegion = selectRegion(resultRegion, corePt1);
                        //Prüfen ob sich in der aufgetrennten Region, in der sich auch Core1 befindet, nur ein Kern befindet
                        coresInSubRegion.Clear();
                        coresInSubRegion = getCoresInSubRegion(subRegion, cellCores);
                        if (coresInSubRegion.Count == 1)
                        {
                            cellCores.RemoveAt(getIndex(corePt1, cellCores));
                            //Es handelt sich um eine abgetrennte Einzelzelle
                            cellData newCell2 = new cellData();
                            newCell2.cellRegion = selectRegion(resultRegion, corePt1);
                            List<cellCoreData> cores2 = new List<cellCoreData>();
                            cores2.Add(getCoreByCoord(corePt1, coresInSubRegion));
                            newCell2.CoreInfo = cores2;
                            //Einzelzelle in globale Liste hinzufügen
                            m_separatedCells.Add(newCell2);

                            //-------------------------------------------------------------------------------------------------------
                            //Wenn noch mind. 2 Kerne für weitere Trennungen übrig sind:
                            //Da nun durch eine Trennlinie 2 neue Zellen entstanden sind, müssen corePt1 und corePt2 neu definiert werden
                            //Zellkern mit dem kleinsten x-Wert als Startkern setzen
                            //-------------------------------------------------------------------------------------------------------
                            if (cellCores.Count > 1)
                            {
                                sortedCoresX = from item in cellCores
                                               orderby item.SP.X ascending
                                               select item;

                                corePt1.X = (int)sortedCoresX.ElementAt(0).SP.X;
                                corePt1.Y = (int)sortedCoresX.ElementAt(0).SP.Y;

                                corePt2 = searchNearestCore(corePt1, sortedCoresX, indexListe, m_invalidCorePairs);

                                corePt1_delta.X = corePt1.X - colOL;
                                corePt1_delta.Y = corePt1.Y - rowOL;
                                corePt2_delta.X = corePt2.X - colOL;
                                corePt2_delta.Y = corePt2.Y - rowOL;

                                //Pfad zwischen den beiden neu definierten Kernen berechnen
                                nodes = m_pfinder.FindPath(corePt1_delta, corePt2_delta);
                            }
                        }
                        //Da muss die Separation so geartet sein, dass kein Zellkern in der 
                        //sub-region existiert
                        else if (coresInSubRegion.Count == 0)
                            break;
                        //In der Region von CorePt1 befinden sich noch mehrere Kerne
                        else
                        {
                            //Wenn nur 2 Kerne in der Region von CorePt1 existieren und kein nächster Core berechnet werden
                            //kann wurde bereits vergeblich versucht zwischen diesen beiden Kernen
                            //zu trennen -> Region trotz mehrerer Zellen als getrennten Zellbereich zurückgeben
                            if (coresInSubRegion.Count == 2)
                            {
                                //Liste aufsteigend nach x sortieren
                                var sortedCoreList = from item in coresInSubRegion
                                                     orderby item.SP.X ascending
                                                     select item;
                                //Nächstgelegenen Kern zu corePt1 suchen in der übrigen Zellclusterregion
                                corePt2 = searchNearestCore(corePt1, sortedCoreList, indexListe, m_invalidCorePairs);
                                if ((corePt2.X == -1) && (corePt2.Y == -1))
                                {
                                    cellData newCell2 = new cellData();
                                    newCell2.cellRegion = subRegion;
                                    List<cellCoreData> cores2 = new List<cellCoreData>();
                                    cores2 = coresInSubRegion;
                                    newCell2.CoreInfo = cores2;
                                    //Einzelzelle in globale Liste hinzufügen
                                    m_separatedCells.Add(newCell2);
                                    //Zellkerne aus Zellkernliste entfernen
                                    cellCores.RemoveAt(getIndex(corePt1, cellCores));
                                }
                            }
                            //Wenn einfach noch mehrere Kerne in der SubRegion sind, den nächsten gültigen zu corePt1 suchen
                            //und corePt2 neu setzen
                            else
                            {
                                //Liste aufsteigend nach x sortieren
                                var sortedCoreList = from item in coresInSubRegion
                                                     orderby item.SP.X ascending
                                                     select item;
                                //Nächstgelegenen Kern zu corePt1 suchen in der übrigen Zellclusterregion
                                corePt2 = searchNearestCore(corePt1, sortedCoreList, indexListe, m_invalidCorePairs);
                                if ((corePt2.X == -1) && (corePt2.Y == -1))
                                    break;
                                //NEU AM 26.10.11 HINZUGEFÜGT!!!!
                                ActivatePathFinder();
                                nodes.Clear();

                                corePt1_delta.X = corePt1.X - colOL;
                                corePt1_delta.Y = corePt1.Y - rowOL;
                                corePt2_delta.X = corePt2.X - colOL;
                                corePt2_delta.Y = corePt2.Y - rowOL;

                                nodes = m_pfinder.FindPath(corePt1_delta, corePt2_delta);
                            }
                        }
                    }
                }
                //Versuchen einen anderen Pfad zu Core2 zu berechnen
                else
                {
                    //List<DoublePoint> separationLinesPoints = getPointsFromSeperationLines(separationLine1, separationLine2);
                    //m_cellField = insertBarrierInPathField(m_cellField, separationLinesPoints);
                    ActivatePathFinder();
                    nodes.Clear();
                    nodes = m_pfinder.FindPath(corePt1_delta, corePt2_delta);
                    if ((nodes == null) || (nodes.Count == 0))
                    {
                        //Kein Pfad zu Core2 ermittelt
                        //Nun den nächstgelegenen Core finden (nicht derzeitigen Core2) zu Core1
                        for (int i = 0; i < sortedCoresX.Count(); i++)
                        {
                            indexListe.Add(getIndex(corePt2, sortedCoresX));
                            corePt2 = searchNearestCore(corePt1, sortedCoresX, indexListe);
                            if ((corePt2.X == -1) && (corePt2.Y == -1))
                            {
                                line spPair = new line();
                                spPair.x1 = corePt1.X;
                                spPair.y1 = corePt1.Y;
                                spPair.x2 = corePt2.X;
                                spPair.y2 = corePt2.Y;
                                m_invalidCorePairs.Add(spPair);
                                isolationFailed = true;

                                break;
                            }
                            corePt2_delta.X = corePt2.X - colOL;
                            corePt2_delta.Y = corePt2.Y - rowOL;
                            nodes = m_pfinder.FindPath(corePt1_delta, corePt2_delta);
                            if (nodes.Count > 0)
                                break;
                            else
                            {
                                line spPair = new line();
                                spPair.x1 = corePt1.X;
                                spPair.y1 = corePt1.Y;
                                spPair.x2 = corePt2.X;
                                spPair.y2 = corePt2.Y;
                                m_invalidCorePairs.Add(spPair);
                                isolationFailed = true;

                                //separateCellsInCluster(cellCores, window);
                                break;
                            }
                        }
                    }
                }
            }
        }
        public void separateCellsInCluster(List<cellCoreData> cellCores, int DCP_AnzEbenen, HWindow window)
        {
            HObject resultRegion;
            HObject subRegion;
            HObject separationLine1;
            HObject separationLine2;
            HTuple areaSubRegion, RowSubRegion, ColSubRegion;
            Point corePt1 = new Point();
            Point corePt2 = new Point();

            if (cellCores.Count <= 1)
                return;
            List<int> indexListe = new List<int>();

            //Zellkern mit dem kleinsten x-Wert als Startkern setzen
            var sortedCoresX = from item in cellCores
                               orderby item.SP.X ascending
                               select item;


            corePt1.X = (int)sortedCoresX.ElementAt(0).SP.X;
            corePt1.Y = (int)sortedCoresX.ElementAt(0).SP.Y;

            corePt2 = searchNearestCore(corePt1, sortedCoresX, indexListe, m_invalidCorePairs);
            //Wenn kein gültiger Kern gefunden wurde, Funktion verlassen
            if ((corePt2.X == -1) && (corePt2.Y == -1))
                return;

            Point corePt1_delta = new Point();
            Point corePt2_delta = new Point();
            corePt1_delta.X = corePt1.X - colOL;
            corePt1_delta.Y = corePt1.Y - rowOL;
            corePt2_delta.X = corePt2.X - colOL;
            corePt2_delta.Y = corePt2.Y - rowOL;

            //Pfad zwischen den beiden Kernen berechnen
            List<PathFinderNode> nodes = m_pfinder.FindPath(corePt1_delta, corePt2_delta);

            while (cellCores.Count() > 0)
            {
                //Wenn corePt2 auf -1/-1 gesetzt wurde, weil es keinen gültigen Kernpartner von corePt1 mehr gibt
                //dann die while Schleife abbrechen
                if ((corePt2.X == -1) && (corePt2.Y == -1))
                    break;
                //Wenn nur ein Kern übrig ist braucht die Fkt. zur Trennung zwischen 2 Kernen nicht aufgerufen werden
                //und brechen die Schleife ab
                if (cellCores.Count() == 1)
                {
                    //MessageBox.Show("Nur ein Kern übrig...springe aus while-schleife");
                    isolationFailed = true;
                    break;
                }
                //HOperatorSet.ClearWindow(window);
                //HOperatorSet.SetPart(window, 0, 0, -1, -1);
                bool sepLinesGenerated = isolateCore(corePt1, corePt2, m_dcpFinder, DCP_AnzEbenen, nodes, m_cell, cellCores, out resultRegion, out separationLine1, out separationLine2, m_HalWindow);
                //bool sepLinesGenerated = isolateCore(corePt1, corePt2, m_dcpFinder, nodes, m_cell, cellCores, out resultRegion, out separationLine1, out separationLine2);
                Application.DoEvents();
                if (sepLinesGenerated == false)
                {
                    //Die Zellkerntrennung soll weiterhin ausgeführt werden mit dem nächsten Zellkernpaar...
                    //D.h. die Koordinaten der aktuellen nicht trennbaren Kerne werden in eine Liste
                    //m_invalidCorePairs gespeichert und danach die Fkt. erneut aufgerufen. Es wird wieder der
                    //linkeste Kern bestimmt und der nächste Nachbar, unter Berücksichtigung der Liste mit den
                    //ungültigen Kernpaaren
                    line spPair = new line();
                    spPair.x1 = corePt1.X;
                    spPair.y1 = corePt1.Y;
                    spPair.x2 = corePt2.X;
                    spPair.y2 = corePt2.Y;
                    m_invalidCorePairs.Add(spPair);
                    isolationFailed = true;

                    separateCellsInCluster(cellCores, DCP_AnzEbenen, window);

                    break;
                }
                if ((separationLine1.CountObj() == 1) && (separationLine2.CountObj() == 1))
                {
                    HOperatorSet.SetColor(window, "pink");
                    HOperatorSet.SetLineWidth(window, 2);
                    HOperatorSet.DispObj(separationLine1, window);
                    HOperatorSet.DispObj(separationLine2, window);
                    HOperatorSet.SetLineWidth(window, 1);
                    //MessageBox.Show("separation lines");
                    //Trennlinien als Hindernisse in die Map einfügen
                    List<DoublePoint> separationLinesPoints = getPointsFromSeperationLines(separationLine1, separationLine2);
                    m_cellField = insertBarrierInPathField(m_cellField, separationLinesPoints);
                    ActivatePathFinder();
                }
                //Prüfen ob die Zellregion aufgetrennt wurde
                if (resultRegion.CountObj() > 1)
                {
                    //Abgetrennte SubClusterRegion ermitteln, in der sich auch Core2 befindet
                    subRegion = selectRegion(resultRegion, corePt2);
                    //Prüfen ob sich in der aufgetrennten Region, in der sich auch Core2 befindet, mehr als ein Kern befindet
                    List<cellCoreData> coresInSubRegion = getCoresInSubRegion(subRegion, cellCores);
                    if (coresInSubRegion.Count > 1)
                    {
                        //Aus der cellCores Liste alle Kerne löschen, die nun in der neuen Liste
                        //coresInSubRegion stehen. Damit wenn die rekursion wieder an die Stelle zurückkommt
                        //auch nur der/die übrig gebliebenen Kerne in der Liste stehen
                        for (int i = 0; i < coresInSubRegion.Count; i++)
                        {
                            for (int j = 0; j < cellCores.Count; j++)
                            {
                                if ((coresInSubRegion[i].SP.X == cellCores[j].SP.X) && (coresInSubRegion[i].SP.Y == cellCores[j].SP.Y))
                                {
                                    cellCores.RemoveAt(j);
                                    break;
                                }
                            }
                        }
                        m_currentCellRegion = subRegion;
                        //Zellen in Sub-Region trennen
                        separateCellsInCluster(coresInSubRegion, DCP_AnzEbenen, window);
                        //Wenn nur ein Kern in einer abgetrennten Region übrig blieb, dann
                        //aus der Liste entfernen und in die Liste der separierten Zellen hinzufügen
                        if (cellCores.Count == 1)
                        {
                            //Es handelt sich um eine abgetrennte Einzelzelle
                            cellData newCell = new cellData();
                            //newCell.cellRegion = cellCores[0].cellCore;
                            newCell.cellRegion = selectRegion(resultRegion, corePt1);
                            List<cellCoreData> cores = new List<cellCoreData>();
                            cores.Add(cellCores[0]);
                            newCell.CoreInfo = cores;
                            //Einzelzelle in globale Liste hinzufügen
                            m_separatedCells.Add(newCell);
                            //Zellkern aus Zellkernliste entfernen
                            cellCores.RemoveAt(0);
                        }
                        else if (cellCores.Count > 1)
                        {
                            //Fall 1: Es sind entweder noch mehrere Kerne in der Region in dieser Rekursionsebene enthalten
                            //Fall 2: Die Region in der sich CorePt1 befindet ist auch schon vom Rest des Clusters abgeschnitten, aber es sind noch Zellkerne
                            //        in einem anderen Teil des Clusters übrig -> Dann müssten corePt1 und corePt2 neu gesetzt werden!
                            //corePt1 bleibt erhalten, corePt2 neu bestimmen

                            //aktuell betrachtete Zellregion neu setzen
                            m_currentCellRegion = selectRegion(resultRegion, corePt1);

                            //wenn in der Region von corePt1 nur ein Kern vorhanden ist handelt es sich um Fall 2, sind > 1 Zellkerne vorhanden Fall 1!
                            List<cellCoreData> coresInSubRegion2 = getCoresInSubRegion(m_currentCellRegion, cellCores);
                            if (coresInSubRegion2.Count > 1)
                            {

                                var sortedCores2 = from item in cellCores
                                                   orderby item.SP.X ascending
                                                   select item;
                                corePt2 = searchNearestCore(corePt1, sortedCores2, indexListe, m_invalidCorePairs);
                                if ((corePt2.X == -1) && (corePt2.Y == -1))
                                    break;
                                corePt2_delta.X = corePt2.X - colOL;
                                corePt2_delta.Y = corePt2.Y - rowOL;

                                nodes.Clear();
                                nodes = m_pfinder.FindPath(corePt1_delta, corePt2_delta);
                                if ((nodes != null) && (nodes.Count != null))
                                {
                                    //
                                }
                                else
                                {
                                    //Probieren ob das klappt:
                                    line spPair = new line();
                                    spPair.x1 = corePt1.X;
                                    spPair.y1 = corePt1.Y;
                                    spPair.x2 = corePt2.X;
                                    spPair.y2 = corePt2.Y;
                                    m_invalidCorePairs.Add(spPair);
                                    isolationFailed = true;

                                    break;
                                }
                            }
                            //Fall 2 hier implementieren
                            else
                            {
                                //Es kann vorkommen, dass in einer vorherigen Rekursion bereits eine Einzelzelle mit dem
                                //hier gesetzten corePt1 generiert wurde. Deshalb zuerst prüfen, ob corePt1 noch in der cellCore
                                //Liste vorhanden ist. Wenn nicht, dann corePt1 und corePt2 ohne Erstellen einer neuen Zelle neu
                                //setzen
                                int index = getIndex(corePt1, cellCores);
                                if (index > -1)
                                {
                                    cellData newCell = new cellData();
                                    newCell.cellRegion = m_currentCellRegion;
                                    List<cellCoreData> cores = new List<cellCoreData>();
                                    cores.Add(getCoreByCoord(corePt1, coresInSubRegion2));
                                    newCell.CoreInfo = cores;
                                    //Einzelzelle in globale Liste hinzufügen
                                    m_separatedCells.Add(newCell);
                                    //Zellkern aus Zellkernliste entfernen
                                    cellCores.RemoveAt(getIndex(corePt1, cellCores));
                                }
                                //corePt1 und corePt2 neu setzen:
                                //Zellkern mit dem kleinsten x-Wert als Startkern setzen
                                sortedCoresX = from item in cellCores
                                               orderby item.SP.X ascending
                                               select item;


                                corePt1.X = (int)sortedCoresX.ElementAt(0).SP.X;
                                corePt1.Y = (int)sortedCoresX.ElementAt(0).SP.Y;

                                corePt2 = searchNearestCore(corePt1, sortedCoresX, indexListe, m_invalidCorePairs);
                                //Wenn kein gültiger Kern gefunden wurde, Funktion verlassen
                                if ((corePt2.X == -1) && (corePt2.Y == -1))
                                    return;

                                corePt1_delta.X = corePt1.X - colOL;
                                corePt1_delta.Y = corePt1.Y - rowOL;
                                corePt2_delta.X = corePt2.X - colOL;
                                corePt2_delta.Y = corePt2.Y - rowOL;

                                //aktuell betrachtete Zellregion neu setzen
                                //m_currentCellRegion = selectRegion(resultRegion, corePt1);
                                //Änderung 09.11.11-> Wenn beide Kerne neu gesetzt werden kann die resultRegion nicht mehr passen
                                //-> einfach die ganze Zellregion zuweisen
                                m_currentCellRegion = m_cell.cellRegion;

                                nodes.Clear();
                                nodes = m_pfinder.FindPath(corePt1_delta, corePt2_delta);
                                if ((nodes != null) && (nodes.Count != null))
                                {
                                    //
                                }
                                else
                                {
                                    //Probieren ob das klappt:
                                    line spPair = new line();
                                    spPair.x1 = corePt1.X;
                                    spPair.y1 = corePt1.Y;
                                    spPair.x2 = corePt2.X;
                                    spPair.y2 = corePt2.Y;
                                    m_invalidCorePairs.Add(spPair);
                                    isolationFailed = true;

                                    break;
                                }
                            }
                        }
                    }
                    else
                    {
                        //Es handelt sich um eine abgetrennte Einzelzelle
                        cellData newCell = new cellData();
                        newCell.cellRegion = subRegion;
                        List<cellCoreData> cores = new List<cellCoreData>();
                        cores.Add(getCoreByCoord(corePt2, coresInSubRegion));
                        newCell.CoreInfo = cores;
                        //Einzelzelle in globale Liste hinzufügen
                        m_separatedCells.Add(newCell);
                        //Zellkern aus Zellkernliste entfernen
                        //MessageBox.Show("vor remove");
                        cellCores.RemoveAt(getIndex(corePt2, cellCores));
                        //Prüfen ob corePt1 auch in einem getrennten Zellbereich liegt
                        //HOperatorSet.SetColor(window, "orange");
                        //HOperatorSet.DispObj(resultRegion, window);
                        //MessageBox.Show("resultRegion");
                        subRegion = selectRegion(resultRegion, corePt1);
                        HOperatorSet.AreaCenter(subRegion, out areaSubRegion, out RowSubRegion, out ColSubRegion);
                        //Wenn der Kernschwerpunkt in keiner Region liegt
                        //Prüfen ob sich in der aufgetrennten Region, in der sich auch Core1 befindet, nur ein Kern befindet
                        coresInSubRegion.Clear();
                        coresInSubRegion = getCoresInSubRegion(subRegion, cellCores);
                        if (coresInSubRegion.Count == 1)
                        {
                            cellCores.RemoveAt(getIndex(corePt1, cellCores));
                            //Es handelt sich um eine abgetrennte Einzelzelle
                            cellData newCell2 = new cellData();
                            newCell2.cellRegion = selectRegion(resultRegion, corePt1);
                            List<cellCoreData> cores2 = new List<cellCoreData>();
                            cores2.Add(getCoreByCoord(corePt1, coresInSubRegion));
                            newCell2.CoreInfo = cores2;
                            //Einzelzelle in globale Liste hinzufügen
                            m_separatedCells.Add(newCell2);

                            //-------------------------------------------------------------------------------------------------------
                            //Wenn noch mind. 2 Kerne für weitere Trennungen übrig sind:
                            //Da nun durch eine Trennlinie 2 neue Zellen entstanden sind, müssen corePt1 und corePt2 neu definiert werden
                            //Zellkern mit dem kleinsten x-Wert als Startkern setzen
                            //-------------------------------------------------------------------------------------------------------
                            if (cellCores.Count > 1)
                            {
                                sortedCoresX = from item in cellCores
                                               orderby item.SP.X ascending
                                               select item;

                                corePt1.X = (int)sortedCoresX.ElementAt(0).SP.X;
                                corePt1.Y = (int)sortedCoresX.ElementAt(0).SP.Y;

                                corePt2 = searchNearestCore(corePt1, sortedCoresX, indexListe, m_invalidCorePairs);

                                corePt1_delta.X = corePt1.X - colOL;
                                corePt1_delta.Y = corePt1.Y - rowOL;
                                corePt2_delta.X = corePt2.X - colOL;
                                corePt2_delta.Y = corePt2.Y - rowOL;

                                //Pfad zwischen den beiden neu definierten Kernen berechnen
                                nodes = m_pfinder.FindPath(corePt1_delta, corePt2_delta);
                            }
                        }
                        //Da muss die Separation so geartet sein, dass kein Zellkern in der 
                        //sub-region existiert
                        else if (coresInSubRegion.Count == 0)
                            break;
                        //In der Region von CorePt1 befinden sich noch mehrere Kerne
                        else
                        {
                            //Wenn nur 2 Kerne in der Region von CorePt1 existieren und kein nächster Core berechnet werden
                            //kann wurde bereits vergeblich versucht zwischen diesen beiden Kernen
                            //zu trennen -> Region trotz mehrerer Zellen als getrennten Zellbereich zurückgeben
                            if (coresInSubRegion.Count == 2)
                            {
                                //Liste aufsteigend nach x sortieren
                                var sortedCoreList = from item in coresInSubRegion
                                                     orderby item.SP.X ascending
                                                     select item;
                                //Nächstgelegenen Kern zu corePt1 suchen in der übrigen Zellclusterregion
                                corePt2 = searchNearestCore(corePt1, sortedCoreList, indexListe, m_invalidCorePairs);
                                if ((corePt2.X == -1) && (corePt2.Y == -1))
                                {
                                    cellData newCell2 = new cellData();
                                    newCell2.cellRegion = subRegion;
                                    List<cellCoreData> cores2 = new List<cellCoreData>();
                                    cores2 = coresInSubRegion;
                                    newCell2.CoreInfo = cores2;
                                    //Einzelzelle in globale Liste hinzufügen
                                    m_separatedCells.Add(newCell2);
                                    //Zellkerne aus Zellkernliste entfernen
                                    cellCores.RemoveAt(getIndex(corePt1, cellCores));
                                }
                            }
                            //Wenn einfach noch mehrere Kerne in der SubRegion sind, den nächsten gültigen zu corePt1 suchen
                            //und corePt2 neu setzen
                            else
                            {
                                //Liste aufsteigend nach x sortieren
                                var sortedCoreList = from item in coresInSubRegion
                                                     orderby item.SP.X ascending
                                                     select item;
                                //Nächstgelegenen Kern zu corePt1 suchen in der übrigen Zellclusterregion
                                corePt2 = searchNearestCore(corePt1, sortedCoreList, indexListe, m_invalidCorePairs);
                                if ((corePt2.X == -1) && (corePt2.Y == -1))
                                    break;

                                //NEU AM 26.10.11 HINZUGEFÜGT!!!!
                                ActivatePathFinder();
                                nodes.Clear();

                                corePt1_delta.X = corePt1.X - colOL;
                                corePt1_delta.Y = corePt1.Y - rowOL;
                                corePt2_delta.X = corePt2.X - colOL;
                                corePt2_delta.Y = corePt2.Y - rowOL;

                                nodes = m_pfinder.FindPath(corePt1_delta, corePt2_delta);
                            }
                        }
                    }
                }
                //Versuchen einen anderen Pfad zu Core2 zu berechnen
                else
                {
                    //List<DoublePoint> separationLinesPoints = getPointsFromSeperationLines(separationLine1, separationLine2);
                    //m_cellField = insertBarrierInPathField(m_cellField, separationLinesPoints);
                    ActivatePathFinder();
                    nodes.Clear();
                    nodes = m_pfinder.FindPath(corePt1_delta, corePt2_delta);
                    if ((nodes == null) || (nodes.Count == 0))
                    {
                        //Kein Pfad zu Core2 ermittelt
                        //Nun den nächstgelegenen Core finden (nicht derzeitigen Core2) zu Core1
                        for (int i = 0; i < sortedCoresX.Count(); i++)
                        {
                            indexListe.Add(getIndex(corePt2, sortedCoresX));
                            corePt2 = searchNearestCore(corePt1, sortedCoresX, indexListe);
                            if ((corePt2.X == -1) && (corePt2.Y == -1))
                            {
                                //Probieren ob das klappt:
                                line spPair = new line();
                                spPair.x1 = corePt1.X;
                                spPair.y1 = corePt1.Y;
                                spPair.x2 = corePt2.X;
                                spPair.y2 = corePt2.Y;
                                m_invalidCorePairs.Add(spPair);
                                isolationFailed = true;

                                break;
                            }
                            corePt2_delta.X = corePt2.X - colOL;
                            corePt2_delta.Y = corePt2.Y - rowOL;
                            nodes = m_pfinder.FindPath(corePt1_delta, corePt2_delta);
                            if (nodes.Count > 0)
                                break;
                            else
                            {
                                //MessageBox.Show("Konnte keinen Pfad erzeugen");

                                //Probieren ob das klappt:
                                line spPair = new line();
                                spPair.x1 = corePt1.X;
                                spPair.y1 = corePt1.Y;
                                spPair.x2 = corePt2.X;
                                spPair.y2 = corePt2.Y;
                                m_invalidCorePairs.Add(spPair);
                                isolationFailed = true;

                                //separateCellsInCluster(cellCores, window);
                                break;
                            }
                        }
                    }
                }
            }
        }
        private int getIndex(Point corePt2, IOrderedEnumerable<cellCoreData> cellCores)
        {
            for (int i = 0; i < cellCores.Count(); i++)
            {
                if (((int)cellCores.ElementAt(i).SP.X == corePt2.X) && ((int)cellCores.ElementAt(i).SP.Y == corePt2.Y))
                    return i;
            }
            return -1;
        }
        private int getIndex(Point corePt2, List<cellCoreData> cellCores)
        {
            for (int i = 0; i < cellCores.Count(); i++)
            {
                if (((int)cellCores[i].SP.X == corePt2.X) && ((int)cellCores[i].SP.Y == corePt2.Y))
                    return i;
            }
            return -1;
        }
        private cellCoreData getCoreByCoord(Point coreCoords, List<cellCoreData> cellCores)
        {
            cellCoreData cellCore = new cellCoreData();

            for (int i = 0; i < cellCores.Count; i++)
            {
                if (((Math.Round(cellCores[i].SP.X) == coreCoords.X) && (Math.Round(cellCores[i].SP.Y) == coreCoords.Y)) ||
                    ((Math.Round(cellCores[i].SP.X) == coreCoords.X) && (Math.Round(cellCores[i].SP.Y) == coreCoords.Y + 1)) ||
                    ((Math.Round(cellCores[i].SP.X) == coreCoords.X) && (Math.Round(cellCores[i].SP.Y) == coreCoords.Y - 1)) ||
                    ((Math.Round(cellCores[i].SP.X) == coreCoords.X - 1) && (Math.Round(cellCores[i].SP.Y) == coreCoords.Y - 1)) ||
                    ((Math.Round(cellCores[i].SP.X) == coreCoords.X - 1) && (Math.Round(cellCores[i].SP.Y) == coreCoords.Y + 1)) ||
                    ((Math.Round(cellCores[i].SP.X) == coreCoords.X - 1) && (Math.Round(cellCores[i].SP.Y) == coreCoords.Y)) ||
                    ((Math.Round(cellCores[i].SP.X) == coreCoords.X + 1) && (Math.Round(cellCores[i].SP.Y) == coreCoords.Y)) ||
                    ((Math.Round(cellCores[i].SP.X) == coreCoords.X + 1) && (Math.Round(cellCores[i].SP.Y) == coreCoords.Y + 1)) ||
                    ((Math.Round(cellCores[i].SP.X) == coreCoords.X + 1) && (Math.Round(cellCores[i].SP.Y) == coreCoords.Y - 1)))
                {
                    return cellCores[i];
                }
            }
            return cellCore;
        }
        public List<cellCoreData> getCoresInSubRegion(HObject subRegion, List<cellCoreData> cellCores)
        {
            HTuple isInside, isInside2, isInside3, isInside4, isInside5, isInside6, isInside7, isInside8, isInside9;

            List<cellCoreData> coresInSubRegion = new List<cellCoreData>();

            for (int i = 0; i < cellCores.Count; i++)
            {
                HOperatorSet.TestRegionPoint(subRegion, cellCores[i].SP.Y, cellCores[i].SP.X, out isInside);
                HOperatorSet.TestRegionPoint(subRegion, cellCores[i].SP.Y, cellCores[i].SP.X, out isInside2);

                HOperatorSet.TestRegionPoint(subRegion, cellCores[i].SP.Y, cellCores[i].SP.X, out isInside);
                HOperatorSet.TestRegionPoint(subRegion, cellCores[i].SP.Y, cellCores[i].SP.X - 2, out isInside2);
                HOperatorSet.TestRegionPoint(subRegion, cellCores[i].SP.Y, cellCores[i].SP.X + 2, out isInside3);
                HOperatorSet.TestRegionPoint(subRegion, cellCores[i].SP.Y + 2, cellCores[i].SP.X, out isInside4);
                HOperatorSet.TestRegionPoint(subRegion, cellCores[i].SP.Y + 2, cellCores[i].SP.X - 2, out isInside5);
                HOperatorSet.TestRegionPoint(subRegion, cellCores[i].SP.Y + 2, cellCores[i].SP.X + 2, out isInside6);
                HOperatorSet.TestRegionPoint(subRegion, cellCores[i].SP.Y - 2, cellCores[i].SP.X, out isInside7);
                HOperatorSet.TestRegionPoint(subRegion, cellCores[i].SP.Y - 2, cellCores[i].SP.X - 2, out isInside8);
                HOperatorSet.TestRegionPoint(subRegion, cellCores[i].SP.Y - 2, cellCores[i].SP.X + 2, out isInside9);
                if (isInside.I == 1 || isInside2.I == 1 || isInside3.I == 1 || isInside4.I == 1 ||
                    isInside5.I == 1 || isInside6.I == 1 || isInside7.I == 1 || isInside8.I == 1 || isInside9.I == 1)
                    coresInSubRegion.Add(cellCores[i]);
            }

            return coresInSubRegion;
        }
        private HObject selectRegion(HObject resultRegion, Point core)
        {
            HTuple isInside, isInside2, isInside3, isInside4, isInside5, isInside6, isInside7, isInside8, isInside9;
            HObject subRegion = null;
            //HOperatorSet.GenEmptyObj(out subRegion);

            for (int i = 0; i < resultRegion.CountObj(); i++)
            {
                HOperatorSet.SelectObj(resultRegion, out subRegion, i + 1);
                HOperatorSet.TestRegionPoint(subRegion, core.Y, core.X, out isInside);
                HOperatorSet.TestRegionPoint(subRegion, core.Y, core.X - 3, out isInside2);
                HOperatorSet.TestRegionPoint(subRegion, core.Y, core.X + 3, out isInside3);
                HOperatorSet.TestRegionPoint(subRegion, core.Y + 3, core.X, out isInside4);
                HOperatorSet.TestRegionPoint(subRegion, core.Y + 3, core.X - 3, out isInside5);
                HOperatorSet.TestRegionPoint(subRegion, core.Y + 3, core.X + 3, out isInside6);
                HOperatorSet.TestRegionPoint(subRegion, core.Y - 3, core.X, out isInside7);
                HOperatorSet.TestRegionPoint(subRegion, core.Y - 3, core.X - 3, out isInside8);
                HOperatorSet.TestRegionPoint(subRegion, core.Y - 3, core.X + 3, out isInside9);
                if (isInside.I == 1 || isInside2.I == 1 || isInside3.I == 1 || isInside4.I == 1 ||
                   isInside5.I == 1 || isInside6.I == 1 || isInside7.I == 1 || isInside8.I == 1 || isInside9.I == 1)
                {
                    return subRegion;
                }
            }
            return subRegion;
        }

        public List<DCP.DoublePoint> GetDCPs(HWindow window, FindSpecialContourPoint algo, cellData cell, int level)
        {
            List<DCP.DoublePoint> DCPList;
            //Special Contour Points finden:
            DCPList = algo.FindAllMaxima(Direction.Left, Direction.Right, Direction.Up, Direction.Down);
            //algo.ShowMaxima(chart1, Direction.Right);
            foreach (DCP.DoublePoint point in DCPList)
            {
                //window.SetColor("black");
                //window.DispCross(point.Y, point.X, 5, 0);
            }
            return DCPList;
        }
        public List<DCP.DoublePoint> GetDCPs(FindSpecialContourPoint algo, cellData cell, int level)
        {
            List<DCP.DoublePoint> DCPList;
            //Special Contour Points finden:
            DCPList = algo.FindAllMaxima(Direction.Left, Direction.Right, Direction.Up, Direction.Down);
            return DCPList;
        }
        private bool isolateCore(Point core1, Point core2, FindSpecialContourPoint algo, int DCP_AnzEbenen, List<PathFinderNode> nodes, cellData cell, List<cellCoreData> validCellCores, out HObject resultRegion, out HObject separationLine1, out HObject separationLine2)
        {
            HObject decisionRegion;
            List<DCP.DoublePoint> DCPList;
            if ((nodes == null) || (nodes.Count == 0))
            {
                resultRegion = null;
                separationLine1 = null;
                separationLine2 = null;
                return false;
            }
            PathFinderNode[] arraynodes = new PathFinderNode[nodes.Count];
            List<PathFinderNode[]> arrayNodeList = new List<PathFinderNode[]>();
            List<Algorithms.PathFinderNode> validNodes;
            List<nodesData> nodesList;

            resultRegion = null;
            HOperatorSet.GenEmptyObj(out separationLine1);
            HOperatorSet.GenEmptyObj(out separationLine2);


            try
            {
                DCPList = GetDCPs(algo, cell, DCP_AnzEbenen);
                //Die ermittelten DCPs als Hinderniskoordinaten in die Pfadmap schreiben, so dass ein Pfad niemals über einen
                //DCP laufen kann, das führt sonst zu Problemen bei der Bestimmung, ob die beiden DCPs auf verschiedenen Seiten
                //des Pfades liegen
                List<DoublePoint> DCPsList = new List<DoublePoint>();
                for (int i = 0; i < DCPList.Count; i++)
                {
                    DoublePoint pt = new DoublePoint();
                    pt.X = DCPList[i].X;
                    pt.Y = DCPList[i].Y;
                    DCPsList.Add(pt);
                }
                m_cellField = insertBarrierInPathField(m_cellField, DCPsList);
                nodes.CopyTo(arraynodes);
                arrayNodeList.Add(arraynodes);
                HOperatorSet.GenEmptyObj(out decisionRegion);
                //getDecisionRegion(core1, core2, algo.CellSegmentation.getContourPoints(), arrayNodeList, out decisionRegion);
                validNodes = checkNodes(arraynodes, validCellCores);

                nodesList = calc_DCP_Distances_To_Valid_Nodes(validNodes, DCPList);

                DCPData firstDCP, secondDCP;
                firstDCP = findFirstDCP(nodesList, m_cell, validCellCores, algo.CellSegmentation.getContourPoints());
                //Zweiten DCP finden, prüfen ob er je nachdem ob DCP1 in/ausserhalb der DecisionRegion liegt
                //den anderen Fall erfüllt und die Verbindungslinie zwischen node und DCP2 keinen Zellkern
                //schneidet. Wenn ungültig, zum Node nächstgelegenen DCP prüfen bis ein gültiger gefunden wurde
                //MessageBox.Show("vor 2.DCP");
                secondDCP = findSecondDCP(firstDCP, nodesList, m_cell, validCellCores, algo.CellSegmentation.getContourPoints(), algo.CellSegmentation.getInnerContourPoints(), decisionRegion);

                if ((secondDCP.X == -1) && (secondDCP.Y == -1))
                {
                    nodesData midPoint;
                    //mittleren Pfadpunkt bestimmen
                    midPoint = getMidpointInPath(nodesList);
                    //Den ersten Contourpoint (CP) bestimmen, der dem mittleren Pfadpunkt am nächsten liegt
                    cellPix CP1, CP2;
                    CP1 = getCP1(midPoint, m_cell, validCellCores, algo.CellSegmentation.getContourPoints());
                    //MessageBox.Show("Ersten CP mit Node verbunden");
                    if ((CP1.x != -1) && (CP1.y != -1))
                        CP2 = getCP2(midPoint, CP1, m_cell, validCellCores, algo.CellSegmentation.getContourPoints(), algo.CellSegmentation.getInnerContourPoints(), decisionRegion);
                    else
                    {
                        CP2.x = -1; CP2.y = -1;
                    }
                    //Wenn kein CP2 gefunden wurde, kann es eigentlich nur noch sein, dass die beiden Kerne dicht beieinander liegen
                    //und der mittlere Node ungünstig liegt, so dass die Trennlinien immer durch etwas Kernregion laufen
                    //Deshalb hier den Node in einer Schleife anders setzen um zu prüfen ob dann eine gültige Trennung
                    //entsteht
                    if ((CP2.x == -1) && (CP2.y == -1))
                    {
                        if (nodesList.Count < 8)
                        {
                            for (int i = 0; i < nodesList.Count; i++)
                            {
                                CP1 = getCP1(nodesList[i], m_cell, validCellCores, algo.CellSegmentation.getContourPoints());
                                if ((CP1.x != -1) && (CP1.y != -1))
                                {
                                    CP2 = getCP2(nodesList[i], CP1, m_cell, validCellCores, algo.CellSegmentation.getContourPoints(), algo.CellSegmentation.getInnerContourPoints(), decisionRegion);
                                    if ((CP2.x != -1) && (CP2.y != -1))
                                        break;
                                }
                            }
                        }
                        else
                        {
                            for (int i = 0; i < nodesList.Count; i = i + 2)
                            {
                                CP1 = getCP1(nodesList[i], m_cell, validCellCores, algo.CellSegmentation.getContourPoints());
                                if ((CP1.x != -1) && (CP1.y != -1))
                                {
                                    CP2 = getCP2(nodesList[i], CP1, m_cell, validCellCores, algo.CellSegmentation.getContourPoints(), algo.CellSegmentation.getInnerContourPoints(), decisionRegion);
                                    if ((CP2.x != -1) && (CP2.y != -1))
                                        break;
                                }
                            }
                        }
                    }
                    if ((CP1.x != -1) && (CP1.y != -1) && (CP2.x != -1) && (CP2.y != -1))
                    {
                        HOperatorSet.GenRegionLine(out separationLine1, CP1.y, CP1.x, midPoint.node.Y + rowOL, midPoint.node.X + colOL);
                        HOperatorSet.GenRegionLine(out separationLine2, CP2.y, CP2.x, midPoint.node.Y + rowOL, midPoint.node.X + colOL);
                        m_separationLinesList.Add(separationLine1);
                        m_separationLinesList.Add(separationLine2);
                        //ResultRegion berechnen. Region nach Abzug der vorher bereits abgetrennten Zellbereiche und der aktuellen Trennlinien
                        bool coresInRegion = getResultRegion(separationLine1, separationLine2, validCellCores, out resultRegion);
                        if (coresInRegion == true)
                            return true;
                        else
                            return false;
                    }
                    else
                        return false;
                }
                else
                {
                    //HOperatorSet.SetColor(Window, "white");
                    HOperatorSet.GenRegionLine(out separationLine1, firstDCP.Y, firstDCP.X, firstDCP.node.Y + rowOL, firstDCP.node.X + colOL);
                    HOperatorSet.GenRegionLine(out separationLine2, secondDCP.Y, secondDCP.X, secondDCP.node.Y + rowOL, secondDCP.node.X + colOL);
                    //HOperatorSet.DispObj(separationLine1, Window);
                    //HOperatorSet.DispObj(separationLine2, Window);
                    m_separationLinesList.Add(separationLine1);
                    m_separationLinesList.Add(separationLine2);
                    //ResultRegion berechnen. Region nach Abzug der vorher bereits abgetrennten Zellbereiche und der aktuellen Trennlinien
                    bool coresInRegion = getResultRegion(separationLine1, separationLine2, validCellCores, out resultRegion);

                    if (coresInRegion == true)
                        return true;
                    else
                        return false;
                }
            }
            catch { }
            {
                return false;
            }
        }
        private bool isolateCore(Point core1, Point core2, FindSpecialContourPoint algo, int DCP_AnzEbenen, List<PathFinderNode> nodes, cellData cell, List<cellCoreData> validCellCores, out HObject resultRegion, out HObject separationLine1, out HObject separationLine2, HWindow Window)
        {
            HObject decisionRegion;
            List<DCP.DoublePoint> DCPList;
            if ((nodes == null) || (nodes.Count == 0))
            {
                resultRegion = null;
                separationLine1 = null;
                separationLine2 = null;
                return false;
            }
            PathFinderNode[] arraynodes = new PathFinderNode[nodes.Count];
            List<PathFinderNode[]> arrayNodeList = new List<PathFinderNode[]>();
            List<Algorithms.PathFinderNode> validNodes;
            List<nodesData> nodesList;

            resultRegion = null;
            HOperatorSet.GenEmptyObj(out separationLine1);
            HOperatorSet.GenEmptyObj(out separationLine2);


            try
            {
                DCPList = GetDCPs(Window, algo, cell, DCP_AnzEbenen);

                //Die ermittelten DCPs als Hinderniskoordinaten in die Pfadmap schreiben, so dass ein Pfad niemals über einen
                //DCP laufen kann, das führt sonst zu Problemen bei der Bestimmung, ob die beiden DCPs auf verschiedenen Seiten
                //des Pfades liegen
                List<DoublePoint> DCPsList = new List<DoublePoint>();
                for (int i = 0; i < DCPList.Count; i++)
                {
                    DoublePoint pt = new DoublePoint();
                    pt.X = DCPList[i].X;
                    pt.Y = DCPList[i].Y;
                    DCPsList.Add(pt);
                }
                int val = m_cellField[86, 53];
                m_cellField = insertBarrierInPathField(m_cellField, DCPsList);
                int val2 = m_cellField[86, 53];
                HOperatorSet.SetColor(Window, "yellow");
                for (int i = 0; i < DCPList.Count; i++)
                {
                    HOperatorSet.DispCross(Window, DCPList[i].Y, DCPList[i].X, 10, 0);
                }
                HOperatorSet.SetColor(Window, "red");
                foreach (var item in nodes)
                {
                    HOperatorSet.DispCross(Window, item.Y + rowOL, item.X + colOL, 1, 0);
                }
                //MessageBox.Show("all nodes in red");
                nodes.CopyTo(arraynodes);
                arrayNodeList.Add(arraynodes);
                HOperatorSet.GenEmptyObj(out decisionRegion);
                //getDecisionRegion(core1, core2, algo.CellSegmentation.getContourPoints(), arrayNodeList, out decisionRegion);
                validNodes = checkNodes(arraynodes, validCellCores);
                Window.SetColor("green");
                foreach (var item in validNodes)
                {
                    HOperatorSet.DispCross(Window, item.Y + rowOL, item.X + colOL, 1, 0);
                }
                //MessageBox.Show("nodes outside coreregion in green");
                Window.SetColor("black");
                HOperatorSet.DispCross(Window, core1.Y, core1.X, 6, 0);
                HOperatorSet.DispCross(Window, core2.Y, core2.X, 6, 0);

                nodesList = calc_DCP_Distances_To_Valid_Nodes(validNodes, DCPList);

                DCPData firstDCP, secondDCP;
                firstDCP = findFirstDCP(nodesList, m_cell, validCellCores, algo.CellSegmentation.getContourPoints());
                Window.SetColor("yellow");
                HOperatorSet.DispCross(Window, firstDCP.Y, firstDCP.X, 10, 0);
                //HOperatorSet.DispLine(Window,firstDCP.Y, firstDCP.X,firstDCP.node.Y+rowOL,firstDCP.node.X+colOL);
                //MessageBox.Show("Ersten DCP mit Node verbunden");
                //Zweiten DCP finden, prüfen ob er je nachdem ob DCP1 in/ausserhalb der DecisionRegion liegt
                //den anderen Fall erfüllt und die Verbindungslinie zwischen node und DCP2 keinen Zellkern
                //schneidet. Wenn ungültig, zum Node nächstgelegenen DCP prüfen bis ein gültiger gefunden wurde
                //MessageBox.Show("vor 2.DCP");
                secondDCP = findSecondDCP(firstDCP, nodesList, m_cell, validCellCores, algo.CellSegmentation.getContourPoints(), algo.CellSegmentation.getInnerContourPoints(), decisionRegion);
                Window.SetColor("yellow");
                HOperatorSet.DispCross(Window, secondDCP.Y, secondDCP.X, 10, 0);
                //MessageBox.Show("weiter");
                if ((secondDCP.X == -1) && (secondDCP.Y == -1))
                {
                    nodesData midPoint;
                    //mittleren Pfadpunkt bestimmen
                    midPoint = getMidpointInPath(nodesList);
                    //Den ersten Contourpoint (CP) bestimmen, der dem mittleren Pfadpunkt am nächsten liegt
                    cellPix CP1, CP2;
                    CP1 = getCP1(midPoint, m_cell, validCellCores, algo.CellSegmentation.getContourPoints());
                    Window.SetColor("cyan");
                    HOperatorSet.DispLine(Window, CP1.y, CP1.x, midPoint.node.Y + rowOL, midPoint.node.X + colOL);
                    //MessageBox.Show("Ersten CP mit Node verbunden");
                    if ((CP1.x != -1) && (CP1.y != -1))
                        CP2 = getCP2(midPoint, CP1, m_cell, validCellCores, algo.CellSegmentation.getContourPoints(), algo.CellSegmentation.getInnerContourPoints(), decisionRegion);
                    else
                    {
                        CP2.x = -1; CP2.y = -1;
                    }
                    //Wenn kein CP2 gefunden wurde, kann es eigentlich nur noch sein, dass die beiden Kerne dicht beieinander liegen
                    //und der mittlere Node ungünstig liegt, so dass die Trennlinien immer durch etwas Kernregion laufen
                    //Deshalb hier den Node in einer Schleife anders setzen um zu prüfen ob dann eine gültige Trennung
                    //entsteht
                    if ((CP2.x == -1) && (CP2.y == -1))
                    {
                        if (nodesList.Count < 8)
                        {
                            for (int i = 0; i < nodesList.Count; i++)
                            {
                                CP1 = getCP1(nodesList[i], m_cell, validCellCores, algo.CellSegmentation.getContourPoints());
                                if ((CP1.x != -1) && (CP1.y != -1))
                                {
                                    HOperatorSet.DispLine(Window, CP1.y, CP1.x, nodesList[i].node.Y + rowOL, nodesList[i].node.X + colOL);
                                    //MessageBox.Show("neuer Midpoint.."+Convert.ToString(CP1.x));
                                    CP2 = getCP2(nodesList[i], CP1, m_cell, validCellCores, algo.CellSegmentation.getContourPoints(), algo.CellSegmentation.getInnerContourPoints(), decisionRegion);
                                    if ((CP2.x != -1) && (CP2.y != -1))
                                        break;
                                }
                            }
                        }
                        else
                        {
                            for (int i = 0; i < nodesList.Count; i = i + 2)
                            {
                                CP1 = getCP1(nodesList[i], m_cell, validCellCores, algo.CellSegmentation.getContourPoints());
                                if ((CP1.x != -1) && (CP1.y != -1))
                                {
                                    HOperatorSet.DispLine(Window, CP1.y, CP1.x, nodesList[i].node.Y + rowOL, nodesList[i].node.X + colOL);
                                    //MessageBox.Show("neuer Midpoint.."+Convert.ToString(CP1.x));
                                    CP2 = getCP2(nodesList[i], CP1, m_cell, validCellCores, algo.CellSegmentation.getContourPoints(), algo.CellSegmentation.getInnerContourPoints(), decisionRegion);
                                    if ((CP2.x != -1) && (CP2.y != -1))
                                        break;
                                }
                            }
                        }
                    }
                    if ((CP1.x != -1) && (CP1.y != -1) && (CP2.x != -1) && (CP2.y != -1))
                    {
                        HOperatorSet.DispLine(Window, CP2.y, CP2.x, midPoint.node.Y + rowOL, midPoint.node.X + colOL);
                        HOperatorSet.GenRegionLine(out separationLine1, CP1.y, CP1.x, midPoint.node.Y + rowOL, midPoint.node.X + colOL);
                        HOperatorSet.GenRegionLine(out separationLine2, CP2.y, CP2.x, midPoint.node.Y + rowOL, midPoint.node.X + colOL);
                        //HOperatorSet.SetColor(Window, "white");
                        //HOperatorSet.DispObj(separationLine1, Window);
                        //HOperatorSet.DispObj(separationLine2, Window);
                        m_separationLinesList.Add(separationLine1);
                        m_separationLinesList.Add(separationLine2);
                        //ResultRegion berechnen. Region nach Abzug der vorher bereits abgetrennten Zellbereiche und der aktuellen Trennlinien
                        bool coresInRegion = getResultRegion(separationLine1, separationLine2, validCellCores, out resultRegion);
                        if (coresInRegion == true)
                            return true;
                        else
                            return false;
                    }
                    else
                        return false;
                }
                else
                {
                    //HOperatorSet.SetColor(Window, "white");
                    HOperatorSet.GenRegionLine(out separationLine1, firstDCP.Y, firstDCP.X, firstDCP.node.Y + rowOL, firstDCP.node.X + colOL);
                    HOperatorSet.GenRegionLine(out separationLine2, secondDCP.Y, secondDCP.X, secondDCP.node.Y + rowOL, secondDCP.node.X + colOL);
                    //HOperatorSet.DispObj(separationLine1, Window);
                    //HOperatorSet.DispObj(separationLine2, Window);
                    m_separationLinesList.Add(separationLine1);
                    m_separationLinesList.Add(separationLine2);
                    //ResultRegion berechnen. Region nach Abzug der vorher bereits abgetrennten Zellbereiche und der aktuellen Trennlinien
                    //HOperatorSet.ClearWindow(Window);
                    //HOperatorSet.SetColor(Window, "cyan");
                    //HOperatorSet.DispObj(m_currentCellRegion, Window);
                    //MessageBox.Show("m_currentCellRegion");
                    bool coresInRegion = getResultRegion(separationLine1, separationLine2, validCellCores, out resultRegion);
                    //HOperatorSet.SetLineWidth(Window, 3);
                    //HOperatorSet.SetColor(Window, "white");
                    //HOperatorSet.SetLineWidth(Window, 1);
                    //HOperatorSet.DispObj(resultRegion, Window);
                    //MessageBox.Show("ResultRegion");
                    if (coresInRegion == true)
                        return true;
                    else
                        return false;
                }
            }
            catch (System.Exception ex)
            {
                return false;
            }
        }
        //ResultRegion berechnen. Region nach Abzug der vorher bereits abgetrennten Zellbereiche und der aktuellen Trennlinien
        //Falls in der Region keine Kerne vorhanden sind false zurückgeben, da somit kein Kern erfolgreich isoliert
        //wurde
        private bool getResultRegion(HObject separationLine1, HObject separationLine2, List<cellCoreData> cellCores, out HObject resultRegion)
        {
            HObject regionUnion, regionDifference, regionDilation;

            HOperatorSet.GenEmptyObj(out regionUnion);
            for (int i = 0; i < m_separationLinesList.Count; i++)
            {
                HOperatorSet.Union2(regionUnion, m_separationLinesList[i], out regionUnion);
            }
            //HOperatorSet.Union2(regionUnion, separationLine2, out regionUnion);
            //HOperatorSet.Union2(regionLine1, regionLine2, out regionUnion);
            HOperatorSet.DilationCircle(regionUnion, out regionDilation, 2.0);
            HOperatorSet.Difference(m_currentCellRegion, regionDilation, out regionDifference);
            HOperatorSet.Connection(regionDifference, out resultRegion);
            //Prüfen ob in der berechneten abgetrennten Region überhaupt Kerne vorhanden sind
            //Wenn nicht dann ist die Isolierung eines Kerns fehlgeschlagen und muss erneut durchgeführt werden
            //unter Berücksichtigung anderer Konstellationen von Pfadpunkten und DCPs
            if (getCoresInSubRegion(resultRegion, cellCores).Count > 0)
                return true;
            else
                return false;
        }
        //Punkt auf der Mitte des Pfades bestimmen
        private nodesData getMidpointInPath(List<nodesData> nodesList)
        {
            nodesData midPoint = new nodesData();

            midPoint = nodesList.ElementAt((int)nodesList.Count() / 2);

            return midPoint;
        }
        //zu jedem gültigen Node eine sortierte Abstandsliste der SCP erstellen und die gültigen nodes dann selber
        //in einer Liste zurückgeben
        List<nodesData> calc_DCP_Distances_To_Valid_Nodes(List<Algorithms.PathFinderNode> validNodes, List<DCP.DoublePoint> SCPs)
        {
            List<nodesData> nodesList = new List<nodesData>();

            for (int i = 0; i < validNodes.Count; i++)
            {
                //Für jeden Pfadpunkt eine neue Liste anlegen,in der die Abstände zu allen SCPs liegen
                List<DCPData> DCPDataList = new List<DCPData>();

                for (int j = 0; j < SCPs.Count; j++)
                {
                    DCPData SCP = new DCPData();
                    SCP.nodeDistance = Math.Sqrt((SCPs[j].X - (validNodes[i].X + colOL)) * (SCPs[j].X - (validNodes[i].X + colOL)) + ((SCPs[j].Y - (validNodes[i].Y + rowOL)) * (SCPs[j].Y - (validNodes[i].Y + rowOL))));
                    SCP.X = SCPs[j].X;
                    SCP.Y = SCPs[j].Y;
                    DCPDataList.Add(SCP);
                }
                //Nun die Liste mit den Distanzwerten sortieren
                var sortedSCPList = from item in DCPDataList
                                    orderby item.nodeDistance ascending
                                    select item;

                nodesData nodedata = new nodesData();
                nodedata.dist_Sorted_SCP_List = sortedSCPList;
                nodedata.node = validNodes[i];
                nodesList.Add(nodedata);
            }
            return nodesList;
        }
        //Nur die Nodes zurückgeben, die nicht in der Zellkernregion liegen
        private List<Algorithms.PathFinderNode> checkNodes(Algorithms.PathFinderNode[] nodes, List<cellCoreData> cellCores)
        {
            HTuple isInside = 0;
            List<Algorithms.PathFinderNode> nodesOutsideCore = new List<Algorithms.PathFinderNode>();
            //List<Algorithms.PathFinderNode> validnodesOutsideCore = new List<Algorithms.PathFinderNode>();
            int count = 0;
            //Die Liste speichert die Indizes der Anfangs und Endpfadpunkte eines zusammenhängenden gültigen
            //Pfadabschnittes
            List<int> indizes = new List<int>();
            for (int i = 0; i < nodes.Length; i++)
            {
                for (int j = 0; j < cellCores.Count; j++)
                {
                    //Als erstes prüfen ob die Kern-SP als node mit aufgeführt sind. Dies kann vorkommen, wenn der SP nicht im Kernbereich
                    //liegt. Deswegen im Vorfeld in jedem Fall die Nodes, mit gleichen Koordinaten wie Kern-SP löschen!
                    HOperatorSet.TestRegionPoint(cellCores[j].cellCore, nodes[i].PY + rowOL.I, nodes[i].PX + colOL.I, out isInside);
                    if ((isInside.I == 1) || ((nodes[i].PY + rowOL.I == (int)cellCores[j].SP.Y) && (nodes[i].PX + colOL.I == (int)cellCores[j].SP.X)))
                    {
                        //Wenn nach dem letzten gültigen Pfadpunkt nun wieder ein ungültiger kommt
                        //letzten Pfadpunkt in die Abschnitt-Liste schreiben
                        if (count > 0)
                        {
                            indizes.Add(i - 1);
                            count = 0;
                        }
                        break;
                    }
                }
                //Wenn der Pfadpunkt nicht in der Zellkernregion liegt übernehmen, sonst nix machen
                if (isInside.I == 0)
                {
                    //Den ersten gültigen Pfadpunkt in die Abschnitt-Liste speichern
                    if (count == 0)
                    {
                        indizes.Add(i);
                    }
                    nodesOutsideCore.Add(nodes[i]);
                    count++;
                }
            }
            //Jetzt nur den Abschnitt übernehmen, der am längsten ist, falls
            //mehr als ein zusammenhängender Abschnitt existiert
            int max = 0;
            int delta;
            int indexAbschnitt = -1;
            if (indizes.Count > 2)
            {
                nodesOutsideCore.Clear();
                for (int i = 0; i < indizes.Count - 1; i++)
                {
                    if (((i + 1) % 2) != 0)
                    {
                        delta = indizes[i + 1] - indizes[i];
                        if (delta > max)
                        {
                            max = delta;
                            indexAbschnitt = i;
                        }
                    }
                }
                for (int i = indizes[indexAbschnitt]; i < indizes[indexAbschnitt] + max; i++)
                {
                    nodesOutsideCore.Add(nodes[i]);
                }
            }
            return nodesOutsideCore;
        }
        private void getDecisionRegion(Point cc1, Point cc2, List<DoublePoint> ContourPoints, List<PathFinderNode[]> arrayNodeList, out HObject region1)
        {
            List<DoublePoint> contour1List = new List<DoublePoint>();
            HObject r1, Line1, Line2;
            r1 = null;
            double minDist = 99999999;
            DoublePoint cp1 = new DoublePoint();
            DoublePoint cp2 = new DoublePoint();
            int index1 = -1;
            int index2 = -1;
            HTuple line1Rows, line2Rows, line1Cols, line2Cols;

            //Konturpunkt mit minimalem Abstand zu Zellkernschwerpunkt 1 finden:
            for (int i = 0; i < ContourPoints.Count; i++)
            {
                if (Math.Sqrt((cc1.X - ContourPoints[i].X) * (cc1.X - ContourPoints[i].X) + (cc1.Y - ContourPoints[i].Y) * (cc1.Y - ContourPoints[i].Y)) < minDist)
                {
                    minDist = Math.Sqrt((cc1.X - ContourPoints[i].X) * (cc1.X - ContourPoints[i].X) + (cc1.Y - ContourPoints[i].Y) * (cc1.Y - ContourPoints[i].Y));
                    cp1.X = ContourPoints[i].X;
                    cp1.Y = ContourPoints[i].Y;
                    index1 = i;
                }
            }
            minDist = 99999999;
            for (int i = 0; i < ContourPoints.Count; i++)
            {
                if (Math.Sqrt((cc2.X - ContourPoints[i].X) * (cc2.X - ContourPoints[i].X) + (cc2.Y - ContourPoints[i].Y) * (cc2.Y - ContourPoints[i].Y)) < minDist)
                {
                    minDist = Math.Sqrt((cc2.X - ContourPoints[i].X) * (cc2.X - ContourPoints[i].X) + (cc2.Y - ContourPoints[i].Y) * (cc2.Y - ContourPoints[i].Y));
                    cp2.X = ContourPoints[i].X;
                    cp2.Y = ContourPoints[i].Y;
                    index2 = i;
                }
            }
            //Jetzt solange Konturpunkte von cp1 übernehmen bis man bei cp2 angekommen ist
            //und zusammen mit allen pfadpunkten eine geschlossene region bilden
            int schranke = ContourPoints.Count + index1;
            int counter = 0;

            for (int i = index1; i < schranke; i++)
            {
                if (i == ContourPoints.Count)
                {
                    i = 0;
                    schranke = ContourPoints.Count - index1;
                }
                //Wenn der zweite Konturpunkt erreicht wurde abbrechen
                if ((ContourPoints[i].X == cp2.X) && (ContourPoints[i].Y == cp2.Y))
                {
                    contour1List.Add(ContourPoints[i]);
                    break;
                }
                contour1List.Add(ContourPoints[i]);
                //HOperatorSet.DispCross(Window, contour1List[counter].y, contour1List[counter].x, 2, 0);
                counter++;
            }

            //Verbindungslinie zwischen Schwerpunkt Zellkern 1 und dem nächsten Konturpunkt herstellen
            //analog für den letzten Zellkern


            HOperatorSet.GenRegionLine(out Line1, cc1.Y, cc1.X, cp1.Y, cp1.X);
            HOperatorSet.GenRegionLine(out Line2, cc2.Y, cc2.X, cp2.Y, cp2.X);

            HOperatorSet.GetRegionPoints(Line1, out line1Rows, out line1Cols);
            HOperatorSet.GetRegionPoints(Line2, out line2Rows, out line2Cols);

            for (int i = 0; i < line1Rows.Length; i++)
            {
                DoublePoint pnt = new DoublePoint();
                pnt.X = line1Cols[i].D;
                pnt.Y = line1Rows[i].D;
                contour1List.Add(pnt);
            }
            //HOperatorSet.DispObj(Line1, Window);
            //HOperatorSet.DispObj(Line2, Window);

            //MessageBox.Show("Lines");

            //Pfadpunkte noch hinzufügen und dann Region bilden ->Pfadpunkte also noch
            //als Inputparam
            for (int i = 0; i < arrayNodeList.Count; i++)
            {
                for (int j = 0; j < arrayNodeList[i].Length; j++)
                {
                    DoublePoint pnt = new DoublePoint();
                    pnt.X = arrayNodeList[i][j].X + colOL;
                    pnt.Y = arrayNodeList[i][j].Y + rowOL;
                    contour1List.Add(pnt);
                }
            }

            for (int i = 0; i < line2Rows.Length; i++)
            {
                DoublePoint pnt = new DoublePoint();
                pnt.X = line2Cols[i].D;
                pnt.Y = line2Rows[i].D;
                contour1List.Add(pnt);
            }

            //Region bilden
            HTuple rows = contour1List[0].Y;
            HTuple cols = contour1List[0].X;
            //HTuple rowsTemp, colsTemp;
            for (int i = 1; i < contour1List.Count; i++)
            {
                HOperatorSet.TupleConcat(rows, contour1List[i].Y, out rows);
                //rows = rowsTemp;
                HOperatorSet.TupleConcat(cols, contour1List[i].X, out cols);
                //cols = colsTemp;
            }
            HOperatorSet.GenRegionPoints(out r1, rows, cols);
            //HOperatorSet.DispObj(r1, Window);
            //HObject r1_dilated;
            //HOperatorSet.DilationCircle(r1, out r1_dilated, 2);
            region1 = r1;
        }
        //Wenn der Kernschwerpunkt in der Liste der Kerne ist, für die keine Trennung möglich ist
        //wird der Listenindex des gefundenen Kernschwerpunktes zurückgegeben
        private bool isCorePairInvalid(Point pt1, Point pt2, List<line> invalidPairs)
        {
            for (int i = 0; i < invalidPairs.Count; i++)
            {
                if ((pt1.X == invalidPairs[i].x1) && (pt1.Y == invalidPairs[i].y1))
                {
                    if ((pt2.X == invalidPairs[i].x2) && (pt2.Y == invalidPairs[i].y2))
                        return true;
                }
                if ((pt1.X == invalidPairs[i].x2) && (pt1.Y == invalidPairs[i].y2))
                {
                    if ((pt2.X == invalidPairs[i].x1) && (pt2.Y == invalidPairs[i].y1))
                        return true;
                }
            }
            return false;
        }
        private Point searchNearestCore(Point pt, IOrderedEnumerable<cellCoreData> ptList, List<int> indexListe)
        {
            double distance;
            double Mindistance = 999999;
            int index = -1;
            bool alreadycalculate = false;
            Point ptListElement = new Point();
            try
            {
                for (int i = 0; i < ptList.Count(); i++)
                {
                    ptListElement.X = (int)ptList.ElementAt(i).SP.X; ptListElement.Y = (int)ptList.ElementAt(i).SP.Y;
                    distance = Math.Sqrt((ptListElement.X - pt.X) * (ptListElement.X - pt.X) + ((ptListElement.Y - pt.Y) * (ptListElement.Y - pt.Y)));
                    if (distance <= 0)
                        distance = 999999;
                    if (distance < Mindistance)
                    {
                        for (int j = 0; j < indexListe.Count; j++)
                        {
                            if (indexListe[j] == i)
                                alreadycalculate = true;
                        }
                        if (alreadycalculate == false)
                        {
                            Mindistance = distance;
                            index = i;
                        }
                        alreadycalculate = false;
                    }
                }
                return (new Point((int)ptList.ElementAt(index).SP.X, (int)ptList.ElementAt(index).SP.Y));
            }
            catch
            {
                return (new Point(-1, -1));
            }
        }
        private Point searchNearestCore(Point pt, IOrderedEnumerable<cellCoreData> ptList, List<int> indexListe, List<line> invalidPairs)
        {
            double distance;
            double Mindistance = 999999;
            int index = -1;
            bool alreadycalculate = false;
            bool foundValidCore = false;
            Point ptListElement = new Point();
            try
            {
                for (int i = 0; i < ptList.Count(); i++)
                {
                    ptListElement.X = (int)ptList.ElementAt(i).SP.X; ptListElement.Y = (int)ptList.ElementAt(i).SP.Y;
                    //Zuerst prüfen ob der SP aus der Liste nicht genommen werden darf, da zw. SP und SP aus Liste
                    //keine Trennung möglich ist
                    if (isCorePairInvalid(pt, ptListElement, invalidPairs) == false)
                    {
                        distance = Math.Sqrt((ptListElement.X - pt.X) * (ptListElement.X - pt.X) + ((ptListElement.Y - pt.Y) * (ptListElement.Y - pt.Y)));
                        if (distance <= 0)
                            distance = 999999;
                        if (distance < Mindistance)
                        {
                            for (int j = 0; j < indexListe.Count; j++)
                            {
                                if (indexListe[j] == i)
                                    alreadycalculate = true;
                            }
                            if (alreadycalculate == false)
                            {
                                Mindistance = distance;
                                index = i;
                                foundValidCore = true;
                            }
                            alreadycalculate = false;
                        }
                    }
                }
                if (foundValidCore == true)
                    return (new Point((int)ptList.ElementAt(index).SP.X, (int)ptList.ElementAt(index).SP.Y));
                else
                    return (new Point(-1, -1));
            }
            catch
            {
                return (new Point(-1, -1));
            }
        }
        byte[,] getByteFieldFromCellCluster(HObject segmentedCellRegions)
        {
            HTuple hv_cellPixel_Row, hv_cellPixel_Col;
            HTuple hv_contourPix_Row, hv_contourPix_Col;
            HObject regionDilation;

            int smallestRecWidth;
            int smallestRecHeight;

            //Kleine Dilatation da sonst an sehr engen Stellen kein Pfad hindurch gefunden wird!
            HOperatorSet.DilationCircle(segmentedCellRegions, out regionDilation, 0.5);

            HOperatorSet.GetRegionPoints(regionDilation, out hv_cellPixel_Row, out hv_cellPixel_Col);
            //HOperatorSet.GenContourRegionXld(segmentedCellRegions, out ho_cellContour, "border");
            HOperatorSet.GetRegionContour(regionDilation, out hv_contourPix_Row, out hv_contourPix_Col);
            //HOperatorSet.GetContourXld(ho_cellContour, out hv_contourPix_Row, out hv_contourPix_Col);
            //HOperatorSet.SetColor(Window, "orange");
            //HOperatorSet.DispObj(ho_cellContour, Window);
            //MessageBox.Show("CellContour für Pfadberechnung...");
            HOperatorSet.SmallestRectangle1(regionDilation, out rowOL, out colOL, out rowUR, out colUR);
            smallestRecWidth = Math.Abs(colUR.I - colOL.I);
            smallestRecHeight = Math.Abs(rowUR.I - rowOL.I);

            byte[,] cellClusterField = new byte[smallestRecWidth, smallestRecHeight];

            for (int j = 0; j < smallestRecHeight; j++)
            {
                for (int i = 0; i < smallestRecWidth; i++)
                {
                    cellClusterField[i, j] = 0;
                }
            }

            //Umschreiben der 1D-Liste in ein 2D-Array
            int currentRow = (int)hv_cellPixel_Row[0].D;
            int x, y;
            for (int index = 0; index < hv_cellPixel_Row.Length; index++)
            {
                if ((int)hv_cellPixel_Row[index].D == currentRow)
                {
                    x = (int)(hv_cellPixel_Col[index].D - colOL.D);
                    y = (int)(hv_cellPixel_Row[index].D - rowOL.D);
                    if (y < 0)
                        y = 0;
                    if (x < 0)
                        x = 0;
                    if (y > smallestRecHeight - 1)
                        y = smallestRecHeight - 1;
                    if (x > smallestRecWidth - 1)
                        x = smallestRecWidth - 1;
                    cellClusterField[x, y] = 1;
                }
                else
                {
                    x = (int)(hv_cellPixel_Col[index].D - colOL.D);
                    y = (int)(hv_cellPixel_Row[index].D - rowOL.D);
                    if (y < 0)
                        y = 0;
                    if (x < 0)
                        x = 0;
                    if (y > smallestRecHeight - 1)
                        y = smallestRecHeight - 1;
                    if (x > smallestRecWidth - 1)
                        x = smallestRecWidth - 1;
                    cellClusterField[x, y] = 1;
                    currentRow = (int)hv_cellPixel_Row[index].D;
                }
            }
            return cellClusterField;
        }

        //Prüfen ob die potentiellen Trennlinien auf gegenüberliegenden Seiten des Pfades liegen
        //Skalarprodukt bilden->muss negativ sein!!
        void testSepPoints(DoublePoint pt1, DoublePoint pt2, DoublePoint pt_node, out bool isSeparated)
        {
            DoublePoint delta1 = new DoublePoint();
            DoublePoint delta2 = new DoublePoint();
            double skalarProd;

            //Prüfen, ob es sich um den selben Punkt handelt. Wenn ja false zurückgeben
            if ((pt1.X == pt2.X) && (pt1.Y == pt2.Y))
                isSeparated = false;

            //Verbindungslinien Vektoren berechnen            
            delta1.X = pt1.X - pt_node.X;
            delta1.Y = pt1.Y - pt_node.Y;

            delta2.X = pt2.X - pt_node.X;
            delta2.Y = pt2.Y - pt_node.Y;

            //Prüfen ob einer der beiden übergebenen Punkte die selben Koordinaten wie der Pfadpunkt hat.
            //Wenn ja wird das Skalarprodukt 0 -> akzeptieren wir so, da derzeit der Pfad auch über einen DCP laufen kann
            //Wenn beide Punkte auf dem Pfad liegen? -> Nicht akzeptieren, auch wenn es theoretisch einen 1 Pixel breiter Übergang geben kann.
            //Problem ist jedoch wenn man das zulassen würde, dass wenn zwei mal der gleiche DCP übergeben wird, dies auch zu einem Skalarprodukt=0 führt
            if (((delta1.X == 0) && (delta1.Y == 0)) || ((delta2.X == 0) && (delta2.Y == 0)))
            {
                isSeparated = true;
            }
            else
            {
                //Skalarprodukt berechnen
                skalarProd = delta1.X * delta2.X + delta1.Y * delta2.Y;

                //mal anders ausrechnen:
                double betrag1, betrag2;

                betrag1 = Math.Sqrt(delta1.X * delta1.X + delta1.Y * delta1.Y);
                betrag2 = Math.Sqrt(delta2.X * delta2.X + delta2.Y * delta2.Y);

                double cosA = skalarProd / (betrag1 * betrag2);

                double skalarProd2 = betrag1 * betrag2 * cosA;

                if (skalarProd < 0)
                    isSeparated = true;
                else
                    isSeparated = false;
            }
        }

        //Findet den nächstgelegenden DCP zum kürzesten vom AStern-Algo berechneten Pfad
        DCPData findFirstDCP(List<nodesData> nodesList, cellData cell, List<cellCoreData> validCellCores, List<DCP.DoublePoint> contourPoints)
        {
            int i;
            int m = 0;
            bool isValid = false;
            bool connectionLineAlreadyUsed = false;
            double minDist, dist;
            DCPData nearestValidSCP = new DCPData();
            nearestValidSCP.X = -1;
            nearestValidSCP.Y = -1;
            HObject regionLine = null;
            HObject regionIntersection, regionLineIntersection;
            HTuple rowCont, colCont, area, rowCont1, colCont1, area1, rowCont2, colCont2, area2;
            List<Point> indexList = new List<Point>();
            Point ind = new Point(-1, -1);

            nearestValidSCP.X = -1; nearestValidSCP.Y = -1;
            int iterator = 0;

            while ((isValid == false) && (iterator <= nodesList.Count()))
            {
                iterator++;
                ind = new Point();
                minDist = 999999999;
                for (i = 0; i < nodesList.Count; i++)
                {
                    //Hier noch durch Schleife mit allen Abständen laufen, da auch ein 2.ter oder 3.ter kleinster Abstand eines
                    //bestimmten Nodes x noch kleiner sein kann, als der kleinste Abstand eines Nodes y
                    for (m = 0; m < nodesList[i].dist_Sorted_SCP_List.Count(); m++)
                    {
                        //Falls der DCP schon ausgewählt wurde, darf er nicht nochmal genommen werden
                        for (int l = 0; l < indexList.Count; l++)
                        {
                            if ((i == indexList[l].X) && (m == indexList[l].Y))
                                connectionLineAlreadyUsed = true;

                        }
                        if ((nodesList[i].dist_Sorted_SCP_List.ElementAt(m).nodeDistance < minDist) && (connectionLineAlreadyUsed == false))
                        {
                            nearestValidSCP.X = nodesList[i].dist_Sorted_SCP_List.ElementAt(m).X;
                            nearestValidSCP.Y = nodesList[i].dist_Sorted_SCP_List.ElementAt(m).Y;
                            nearestValidSCP.nodeDistance = nodesList[i].dist_Sorted_SCP_List.ElementAt(m).nodeDistance;
                            nearestValidSCP.node = nodesList[i].node;
                            minDist = nodesList[i].dist_Sorted_SCP_List.ElementAt(m).nodeDistance;
                            ind.X = i; ind.Y = m;
                        }
                        connectionLineAlreadyUsed = false;
                    }
                }
                indexList.Add(ind);
                //Prüfen ob die Verbindungslinie des gefundenen nächsten DCP zu dem entspr. Pfadpunkt (node) 
                //eine Kenrregion schneidet
                bool intersection = false;
                for (int k = 0; k < allCoresInCell.Count; k++)
                {
                    HOperatorSet.GenRegionLine(out regionLine, nearestValidSCP.Y, nearestValidSCP.X, nearestValidSCP.node.Y + rowOL, nearestValidSCP.node.X + colOL);
                    HOperatorSet.Intersection(allCoresInCell[k].cellCore, regionLine, out regionIntersection);
                    HOperatorSet.AreaCenter(regionIntersection, out area, out rowCont, out colCont);
                    //Prüfen ob die ganze Verbindungslinie in der Zelle liegt. Sie darf max. 10Pix durch die Zellfläche verlassen 
                    HOperatorSet.Intersection(cell.cellRegion, regionLine, out regionLineIntersection);
                    HOperatorSet.AreaCenter(regionLine, out area1, out rowCont1, out colCont1);
                    HOperatorSet.AreaCenter(regionLineIntersection, out area2, out rowCont2, out colCont2);

                    if ((area > 0) || (area2 < (area1 - 10)))
                    {
                        intersection = true;
                        nearestValidSCP.X = -1;
                        nearestValidSCP.Y = -1;
                        nearestValidSCP.nodeDistance = -1;
                        //counter++;
                    }
                }
                if (intersection == false)
                {
                    isValid = true;
                }
            }
            if ((nearestValidSCP.X != -1) && (nearestValidSCP.Y != -1) && (nearestValidSCP.nodeDistance >= 25))
            {
                ind = new Point(-1, -1);
                minDist = 11;

                //Wenn ein DCP mit mehr als 25Pix Entfernung zum Node gefunden wurde, nun noch prüfen, 
                //ob ein normaler Konturpunkt <= 10 Pix Abstand zu irgendeinem gültigen Pfadpunkt besitzt
                for (i = 0; i < nodesList.Count; i = i + 4)
                {
                    for (int j = 0; j < contourPoints.Count; j = j + 10)
                    {
                        dist = Math.Abs(contourPoints[j].X - (nodesList[i].node.X + colOL.I)) + Math.Abs(contourPoints[j].Y - (nodesList[i].node.Y + rowOL.I));
                        if (dist < minDist)
                        {
                            for (int k = 0; k < allCoresInCell.Count; k++)
                            {
                                HOperatorSet.GenRegionLine(out regionLine, contourPoints[j].Y, contourPoints[j].X, nodesList[i].node.Y + rowOL, nodesList[i].node.X + colOL);
                                HOperatorSet.Intersection(allCoresInCell[k].cellCore, regionLine, out regionIntersection);
                                HOperatorSet.AreaCenter(regionIntersection, out area, out rowCont, out colCont);
                                //Prüfen ob die ganze Verbindungslinie in der Zelle liegt. Sie darf max. 10Pix durch die Zellfläche verlassen 
                                HOperatorSet.Intersection(cell.cellRegion, regionLine, out regionLineIntersection);
                                HOperatorSet.AreaCenter(regionLine, out area1, out rowCont1, out colCont1);
                                HOperatorSet.AreaCenter(regionLineIntersection, out area2, out rowCont2, out colCont2);

                                if ((area.I == 0) && (area2.I >= (area1.I - 10)))
                                {
                                    ind.X = i;
                                    ind.Y = j;
                                    minDist = dist;
                                }
                            }
                        }
                    }
                }
                if ((ind.X != -1) && (ind.Y != -1))
                {
                    nearestValidSCP.X = contourPoints[ind.Y].X;
                    nearestValidSCP.Y = contourPoints[ind.Y].Y;
                    nearestValidSCP.node = nodesList[ind.X].node;
                    nearestValidSCP.nodeDistance = minDist;
                    return nearestValidSCP;
                }
            }
            return nearestValidSCP;
        }

        private DCPData findSecondDCP(DCPData firstSCP, List<nodesData> nodesList, cellData cell, List<cellCoreData> validCellCores, List<DCP.DoublePoint> contourPoints, List<DCP.DoublePoint> innerContourPoints, HObject decisionRegion)
        {
            int i;
            int index = -1;
            int ind = -1;
            int iterator = 0;
            bool isValid = false;
            bool connectionLineAlreadyUsed = false;
            bool intersection = false;
            bool alreadyUsed = false;
            double minDist;
            double dist;

            DoublePoint pt1 = new DoublePoint();
            DoublePoint pt2 = new DoublePoint();
            DoublePoint pt_node = new DoublePoint();

            HObject regionLine = null;
            HObject regionIntersection, regionLineIntersection;
            HTuple rowCont, colCont, area, rowCont1, colCont1, area1, rowCont2, colCont2, area2, isInside;
            List<int> indexList = new List<int>();
            List<int> alreadyCheckedIndexes = new List<int>();

            DCPData secondSCP = new DCPData();
            secondSCP.X = -1;
            secondSCP.Y = -1;

            pt1.X = firstSCP.X;
            pt1.Y = firstSCP.Y;
            pt_node.X = firstSCP.node.X + colOL;
            pt_node.Y = firstSCP.node.Y + rowOL;

            if ((firstSCP.X == -1) && (firstSCP.Y == -1))
                return secondSCP;
            //Prüfen ob der erste DCP in oder ausserhalb der decision-Region ist. Der zweite SCP muss
            //dann entsprechend das Gegenteil erfüllen.
            //HOperatorSet.TestRegionPoint(decisionRegion, firstSCP.Y, firstSCP.X, out isInside);
            //firstSCPInside = Convert.ToBoolean(isInside.O);

            //Übergebenen Node in der Liste wiederfinden um den Index zu erhalten
            for (int j = 0; j < nodesList.Count; j++)
            {
                if ((firstSCP.node.X == nodesList[j].node.X) && (firstSCP.node.Y == nodesList[j].node.Y))
                {
                    index = j;
                    break;
                }
            }
            minDist = 40;
            double distance = -1;
            iterator++;
            //--------------------------------------------------------------------------------------
            //Zuerst prüfen ob ein normaler Konturpunkt ganz nahe (<=40Pix) am gewähltem Pfadpunkt
            //liegt. Wenn ja, dann diesen CP als DCP2 übernehmen.
            //--------------------------------------------------------------------------------------
            while ((isValid == false) && (iterator <= 100))
            {
                iterator++;
                for (i = 0; i < contourPoints.Count; i = i + 10)
                {
                    alreadyUsed = false;
                    //Prüfen ob der aktuelle Konturpunkt schon mal genommen wurde
                    for (int l = 0; l < alreadyCheckedIndexes.Count; l++)
                    {
                        if (alreadyCheckedIndexes[l] == i)
                        {
                            alreadyUsed = true;
                            break;
                        }
                    }
                    if (alreadyUsed == false)
                    {
                        distance = Math.Sqrt((((firstSCP.node.X + colOL) - contourPoints[i].X) * ((firstSCP.node.X + colOL) - contourPoints[i].X)) + (((firstSCP.node.Y + rowOL) - contourPoints[i].Y) * ((firstSCP.node.Y + rowOL) - contourPoints[i].Y)));
                        if (distance <= minDist)
                        {
                            //Prüfen ob der CP auf der anderen Seite des Pfades liegt wie DCP1
                            //HOperatorSet.TestRegionPoint(decisionRegion, contourPoints[i].Y, contourPoints[i].X, out isInside);
                            //secondSCPInside = Convert.ToBoolean(isInside.O);
                            bool isSeparated;
                            pt2.X = contourPoints[i].X;
                            pt2.Y = contourPoints[i].Y;
                            testSepPoints(pt1, pt2, pt_node, out isSeparated);
                            if (isSeparated == true)
                            {
                                ind = i;
                                minDist = distance;
                                secondSCP.X = contourPoints[ind].X;
                                secondSCP.Y = contourPoints[ind].Y;
                                secondSCP.nodeDistance = minDist;
                                secondSCP.node = firstSCP.node;
                            }
                        }
                    }
                }
                if ((secondSCP.X != -1) && (secondSCP.Y != -1))
                {
                    //Prüfen ob die Verbindungslinie keinen Zellkern oder Hintergrund schneidet:
                    intersection = false;
                    for (int k = 0; k < allCoresInCell.Count; k++)
                    {
                        HOperatorSet.GenRegionLine(out regionLine, secondSCP.Y, secondSCP.X, secondSCP.node.Y + rowOL, secondSCP.node.X + colOL);
                        HOperatorSet.Intersection(allCoresInCell[k].cellCore, regionLine, out regionIntersection);
                        HOperatorSet.AreaCenter(regionIntersection, out area, out rowCont, out colCont);
                        //Prüfen ob innenliegende Löcher durchlaufen werden
                        HOperatorSet.Intersection(cell.cellRegion, regionLine, out regionLineIntersection);
                        HOperatorSet.AreaCenter(regionLine, out area1, out rowCont1, out colCont1);
                        HOperatorSet.AreaCenter(regionLineIntersection, out area2, out rowCont2, out colCont2);

                        if ((area > 0) || (area2.I < (area1.I - 10)))
                        {
                            //HOperatorSet.SetColor(Window, "red");
                            //HOperatorSet.DispObj(regionLine, Window);
                            intersection = true;
                            secondSCP.X = -1;
                            secondSCP.Y = -1;
                            secondSCP.nodeDistance = -1;
                            minDist = 20;
                            alreadyCheckedIndexes.Add(ind);
                            break;
                        }
                    }
                    if (intersection == false)
                    {
                        isValid = true;
                    }
                }
                else
                    break;
            }
            if ((secondSCP.X != -1) && (secondSCP.Y != -1))
                return secondSCP;

            iterator = 0;
            //--------------------------------------------------------------------------
            //Wenn kein naher CP gefunden wurde, versuchen einen DCP zu finden
            //--------------------------------------------------------------------------
            while (((isValid == false) && (iterator <= nodesList[index].dist_Sorted_SCP_List.Count())))
            {
                iterator++;
                ind = -1;
                minDist = 999999999;
                for (i = 0; i < nodesList[index].dist_Sorted_SCP_List.Count(); i++)
                {
                    connectionLineAlreadyUsed = false;
                    //Falls der SCP schon ausgewählt wurde, darf er nicht nochmal genommen werden
                    for (int l = 0; l < indexList.Count; l++)
                    {
                        if (i == indexList[l])
                            connectionLineAlreadyUsed = true;

                    }
                    if ((nodesList[index].dist_Sorted_SCP_List.ElementAt(i).nodeDistance < minDist) && (connectionLineAlreadyUsed == false))
                    {
                        //HOperatorSet.TestRegionPoint(decisionRegion, nodesList[index].dist_Sorted_SCP_List.ElementAt(i).Y, nodesList[index].dist_Sorted_SCP_List.ElementAt(i).X, out isInside);
                        //secondSCPInside = Convert.ToBoolean(isInside.O);
                        //if (firstSCPInside != secondSCPInside)
                        bool isSeparated;
                        pt2.X = nodesList[index].dist_Sorted_SCP_List.ElementAt(i).X;
                        pt2.Y = nodesList[index].dist_Sorted_SCP_List.ElementAt(i).Y;
                        testSepPoints(pt1, pt2, pt_node, out isSeparated);
                        if (isSeparated == true)
                        {
                            minDist = nodesList[index].dist_Sorted_SCP_List.ElementAt(i).nodeDistance;
                            secondSCP.X = nodesList[index].dist_Sorted_SCP_List.ElementAt(i).X;
                            secondSCP.Y = nodesList[index].dist_Sorted_SCP_List.ElementAt(i).Y;
                            secondSCP.nodeDistance = nodesList[index].dist_Sorted_SCP_List.ElementAt(i).nodeDistance;
                            secondSCP.node = nodesList[index].node;
                            ind = i;
                            break;
                        }
                    }
                }
                indexList.Add(ind);
                //Prüfen ob die Verbindungslinie des gefundenen nächsten SCP zu dem entspr. Pfadpunkt (node) 
                //eine Ellipsenregion schneidet
                //HOperatorSet.GenRegionLine(out regionLine, nearestValidSCP.Y + rowOL.I, nearestValidSCP.X + colOL.I, nearestValidSCP.node.PY + rowOL.I, nearestValidSCP.node.PX + colOL.I);
                //HOperatorSet.GenRegionLine(out regionLine, nearestValidSCP.Y, nearestValidSCP.X, nearestValidSCP.node.Y + rowOL, nearestValidSCP.node.X + colOL);

                intersection = false;
                if ((secondSCP.X != -1) && (secondSCP.Y != -1))
                {
                    for (int k = 0; k < allCoresInCell.Count; k++)
                    {
                        HOperatorSet.GenRegionLine(out regionLine, secondSCP.Y, secondSCP.X, secondSCP.node.Y + rowOL, secondSCP.node.X + colOL);
                        HOperatorSet.Intersection(allCoresInCell[k].cellCore, regionLine, out regionIntersection);
                        HOperatorSet.AreaCenter(regionIntersection, out area, out rowCont, out colCont);
                        //Prüfen ob innenliegende Löcher durchlaufen werden
                        HOperatorSet.Intersection(cell.cellRegion, regionLine, out regionLineIntersection);
                        HOperatorSet.AreaCenter(regionLine, out area1, out rowCont1, out colCont1);
                        HOperatorSet.AreaCenter(regionLineIntersection, out area2, out rowCont2, out colCont2);

                        if ((area > 0) || (area2.I < (area1.I - 10)))
                        {
                            //HOperatorSet.SetColor(Window, "red");
                            //HOperatorSet.DispObj(regionLine, Window);
                            intersection = true;
                            secondSCP.X = -1;
                            secondSCP.Y = -1;
                            secondSCP.nodeDistance = -1;
                            break;
                        }
                    }
                    if (intersection == false)
                    {
                        isValid = true;
                    }
                }
            }
            intersection = false;
            //Prüfen ob es noch einen innenliegenden Konturpunkt von Löchern gibt,
            //der näher als der gewählte DCP am Node liegt und somit als ein Endpunkt
            //für die Trennlinie genommen werden sollte
            iterator = 0;
            alreadyCheckedIndexes.Clear();
            ind = -1;
            if ((secondSCP.X != -1) && (secondSCP.Y != -1))
            {
                DCPData tempSecondDCP = new DCPData();
                tempSecondDCP = secondSCP;
                isValid = false;

                while ((isValid == false) && (iterator <= innerContourPoints.Count))
                {
                    iterator++;
                    for (int k = 0; k < innerContourPoints.Count; k++)
                    {
                        alreadyUsed = false;
                        //Prüfen ob der aktuelle Konturpunkt schon mal genommen wurde
                        for (int l = 0; l < alreadyCheckedIndexes.Count; l++)
                        {
                            if (alreadyCheckedIndexes[l] == k)
                            {
                                alreadyUsed = true;
                                break;
                            }
                        }
                        if (alreadyUsed == false)
                        {
                            dist = Math.Sqrt((innerContourPoints[k].X - (firstSCP.node.X + colOL)) * (innerContourPoints[k].X - (firstSCP.node.X + colOL)) + (innerContourPoints[k].Y - (firstSCP.node.Y + rowOL)) * (innerContourPoints[k].Y - (firstSCP.node.Y + rowOL)));
                            if (dist < secondSCP.nodeDistance)
                            {
                                //HOperatorSet.TestRegionPoint(decisionRegion, innerContourPoints[k].Y, innerContourPoints[k].X, out isInside);
                                //secondSCPInside = Convert.ToBoolean(isInside.O);
                                //if (firstSCPInside != secondSCPInside)
                                //{
                                bool isSeparated;
                                pt2.X = innerContourPoints[k].X;
                                pt2.Y = innerContourPoints[k].Y;
                                testSepPoints(pt1, pt2, pt_node, out isSeparated);
                                if (isSeparated == true)
                                {
                                    secondSCP.X = innerContourPoints[k].X;
                                    secondSCP.Y = innerContourPoints[k].Y;
                                    secondSCP.nodeDistance = dist;
                                    ind = k;
                                }
                            }
                        }
                    }
                    //Prüfen ob die Verbindungslinie einen Zellkern oder Hintergrund schneidet
                    for (int k = 0; k < allCoresInCell.Count; k++)
                    {
                        HOperatorSet.GenRegionLine(out regionLine, secondSCP.Y, secondSCP.X, secondSCP.node.Y + rowOL, secondSCP.node.X + colOL);
                        HOperatorSet.Intersection(allCoresInCell[k].cellCore, regionLine, out regionIntersection);
                        HOperatorSet.AreaCenter(regionIntersection, out area, out rowCont, out colCont);
                        //Prüfen ob innenliegende Löcher durchlaufen werden
                        HOperatorSet.Intersection(cell.cellRegion, regionLine, out regionLineIntersection);
                        HOperatorSet.AreaCenter(regionLine, out area1, out rowCont1, out colCont1);
                        HOperatorSet.AreaCenter(regionLineIntersection, out area2, out rowCont2, out colCont2);

                        if ((area > 0) || (area2.I < (area1.I - 10)))
                        {
                            intersection = true;
                            //ursprüngliche Daten des gefundenen DCP2 wiederherstellen
                            secondSCP.X = tempSecondDCP.X;
                            secondSCP.Y = tempSecondDCP.Y;
                            secondSCP.nodeDistance = tempSecondDCP.nodeDistance;
                            alreadyCheckedIndexes.Add(ind);
                        }
                    }
                    if (intersection == false)
                    {
                        isValid = true;
                    }
                }
            }
            //Prüfen ob es einen inneren Konturpunkt gibt, falls es keinen gültigen DCP gibt
            intersection = false;
            iterator = 0;
            alreadyCheckedIndexes.Clear();
            ind = -1;
            if ((secondSCP.X == -1) && (secondSCP.Y == -1))
            {
                secondSCP.nodeDistance = 9999999;
                if (innerContourPoints.Count > 0)
                {
                    while ((isValid == false) && (iterator <= innerContourPoints.Count / 10))
                    {
                        iterator++;
                        if (innerContourPoints.Count < 300)
                        {
                            for (int k = 0; k < innerContourPoints.Count; k = k + 5)
                            {
                                alreadyUsed = false;
                                //Prüfen ob der aktuelle Konturpunkt schon mal genommen wurde
                                for (int l = 0; l < alreadyCheckedIndexes.Count; l++)
                                {
                                    if (alreadyCheckedIndexes[l] == k)
                                    {
                                        alreadyUsed = true;
                                        break;
                                    }
                                    else
                                        alreadyUsed = false;
                                }
                                if (alreadyUsed == false)
                                {
                                    dist = Math.Sqrt((innerContourPoints[k].X - (firstSCP.node.X + colOL)) * (innerContourPoints[k].X - (firstSCP.node.X + colOL)) + (innerContourPoints[k].Y - (firstSCP.node.Y + rowOL)) * (innerContourPoints[k].Y - (firstSCP.node.Y + rowOL)));
                                    if (dist < secondSCP.nodeDistance)
                                    {
                                        //HOperatorSet.TestRegionPoint(decisionRegion, innerContourPoints[k].Y, innerContourPoints[k].X, out isInside);
                                        //secondSCPInside = Convert.ToBoolean(isInside.O);
                                        //if (firstSCPInside != secondSCPInside)
                                        //{
                                        bool isSeparated;
                                        pt2.X = innerContourPoints[k].X;
                                        pt2.Y = innerContourPoints[k].Y;
                                        testSepPoints(pt1, pt2, pt_node, out isSeparated);
                                        if (isSeparated == true)
                                        {
                                            secondSCP.X = innerContourPoints[k].X;
                                            secondSCP.Y = innerContourPoints[k].Y;
                                            secondSCP.nodeDistance = dist;
                                            ind = k;
                                        }
                                    }
                                }
                            }
                        }
                        else
                        {
                            for (int k = 0; k < innerContourPoints.Count; k = k + 30)
                            {
                                alreadyUsed = false;
                                //Prüfen ob der aktuelle Konturpunkt schon mal genommen wurde
                                for (int l = 0; l < alreadyCheckedIndexes.Count; l++)
                                {
                                    if (alreadyCheckedIndexes[l] == k)
                                    {
                                        alreadyUsed = true;
                                        break;
                                    }
                                    else
                                        alreadyUsed = false;
                                }
                                if (alreadyUsed == false)
                                {
                                    dist = Math.Sqrt((innerContourPoints[k].X - (firstSCP.node.X + colOL)) * (innerContourPoints[k].X - (firstSCP.node.X + colOL)) + (innerContourPoints[k].Y - (firstSCP.node.Y + rowOL)) * (innerContourPoints[k].Y - (firstSCP.node.Y + rowOL)));
                                    if (dist < secondSCP.nodeDistance)
                                    {
                                        //HOperatorSet.TestRegionPoint(decisionRegion, innerContourPoints[k].Y, innerContourPoints[k].X, out isInside);
                                        //secondSCPInside = Convert.ToBoolean(isInside.O);
                                        //if (firstSCPInside != secondSCPInside)
                                        //{
                                        bool isSeparated;
                                        pt2.X = innerContourPoints[k].X;
                                        pt2.Y = innerContourPoints[k].Y;
                                        testSepPoints(pt1, pt2, pt_node, out isSeparated);
                                        if (isSeparated == true)
                                        {
                                            secondSCP.X = innerContourPoints[k].X;
                                            secondSCP.Y = innerContourPoints[k].Y;
                                            secondSCP.nodeDistance = dist;
                                            ind = k;
                                        }
                                    }
                                }
                            }
                        }
                        //Prüfen ob die Verbindungslinie einen Zellkern oder Hintergrund schneidet
                        for (int k = 0; k < allCoresInCell.Count; k++)
                        {
                            HOperatorSet.GenRegionLine(out regionLine, secondSCP.Y, secondSCP.X, secondSCP.node.Y + rowOL, secondSCP.node.X + colOL);
                            HOperatorSet.Intersection(allCoresInCell[k].cellCore, regionLine, out regionIntersection);
                            HOperatorSet.AreaCenter(regionIntersection, out area, out rowCont, out colCont);
                            //Prüfen ob innenliegende Löcher durchlaufen werden
                            HOperatorSet.Intersection(cell.cellRegion, regionLine, out regionLineIntersection);
                            HOperatorSet.AreaCenter(regionLine, out area1, out rowCont1, out colCont1);
                            HOperatorSet.AreaCenter(regionLineIntersection, out area2, out rowCont2, out colCont2);

                            if ((area > 0) || (area2.I < (area1.I - 10)))
                            {
                                intersection = true;
                                //ursprüngliche Daten des gefundenen DCP2 wiederherstellen
                                secondSCP.X = -1;
                                secondSCP.Y = -1;
                                secondSCP.nodeDistance = 9999999;
                                alreadyCheckedIndexes.Add(ind);
                            }
                        }
                        if (intersection == false)
                        {
                            isValid = true;
                        }
                    }
                }
            }
            if ((secondSCP.X == -1) && (secondSCP.Y == -1))
            {
                alreadyCheckedIndexes.Clear();
                iterator = 0;
                ind = -1;
                intersection = false;
                secondSCP.node = firstSCP.node;
                double actminDist = 9999999;
                //Prüfen ob es einen normalen Konturpunkt gibt, falls es keinen gültigen DCP gibt.
                //Falls vorher schon ein innerer Konturpunkt gefunden wurde, werden die beiden
                //Distanzen zum Node vergleichen und der Konturpunkt mit der geringeren Distanz übernommen
                //MessageBox.Show("Kein DCP oder inneren CP gefunden, suche nach normalem CP!");

                //-------------------------------------------------------------------------------------------------------------
                //ÄNDERUNG: 26.10.11 -> Es wird hier abgefragt ob noch kein zweiter DCP vorhanden ist, demnach gibt es
                //keinen vorher ermittelten inneren Konturpunkt als DCP -> Änderung in Abfrage über Distanz vornehmen, da die
                //aktuell berechnete Distanz immer kleiner ist als secondSCP.nodeDistance, denn die ist auf 9999999 eingestellt
                //wenn kein zweiter DCP gefunden wurde
                //-------------------------------------------------------------------------------------------------------------

                while ((isValid == false) && (iterator <= 100))
                {
                    iterator++;
                    actminDist = 9999999;
                    for (int k = 0; k < contourPoints.Count; k = k + 2)
                    {
                        alreadyUsed = false;
                        //Prüfen ob der aktuelle Konturpunkt schon mal genommen wurde
                        for (int l = 0; l < alreadyCheckedIndexes.Count; l++)
                        {
                            if (alreadyCheckedIndexes[l] == k)
                            {
                                alreadyUsed = true;
                                break;
                            }
                            else
                                alreadyUsed = false;
                        }
                        if (alreadyUsed == false)
                        {
                            dist = Math.Sqrt((contourPoints[k].X - (firstSCP.node.X + colOL)) * (contourPoints[k].X - (firstSCP.node.X + colOL)) + (contourPoints[k].Y - (firstSCP.node.Y + rowOL)) * (contourPoints[k].Y - (firstSCP.node.Y + rowOL)));
                            //if (dist < secondSCP.nodeDistance)
                            //ÄNDERUNG 26.10.11
                            if (dist < actminDist)
                            {
                                actminDist = dist;
                                ind = k;
                                //Da es sich bei den Konturpunkten um float-Werte handelt und TestRegionPoint aber nur ganzzahlige Pixel betrachtet
                                //kann es bei ganz engen Zellbereichen dazu führen das CP, die ganz dicht an der DecisionRegion auf der anderen
                                //Seite als DCP1 liegen, trotzdem nicht so getestet werden. Deshalb die konvertierung der X- bzw. Y-Werte nach int
                                //um so in sehr engen Zellbereichen trotzdem einen gültigen CP ermitteln zu können
                                //-> bringt eigentlich auch nix, da so CP auf der gleichen Seite wie DCP1 ausgewählt werden....
                                //durch die neue Pfadberechnung wird allerdings nach einigen Anläufen die Zelle richtig abgetrennt...

                                //ÄNDERUNG AM 26.10.11 -> NACHFOLGENDES AUSKOMMENTIERT UND NACH DER SCHLEIFE EINGEBAUT

                                //bool isSeparated;
                                //pt2.X = contourPoints[k].X;
                                //pt2.Y = contourPoints[k].Y;
                                //testSepPoints(pt1, pt2, pt_node, out isSeparated);
                                //if (isSeparated == true)
                                //{
                                //    secondSCP.X = contourPoints[k].X;
                                //    secondSCP.Y = contourPoints[k].Y;
                                //    secondSCP.nodeDistance = dist;
                                //    ind = k;
                                //}
                            }
                        }
                    }
                    //Da es sich bei den Konturpunkten um float-Werte handelt und TestRegionPoint aber nur ganzzahlige Pixel betrachtet
                    //kann es bei ganz engen Zellbereichen dazu führen das CP, die ganz dicht an der DecisionRegion auf der anderen
                    //Seite als DCP1 liegen, trotzdem nicht so getestet werden. Deshalb die konvertierung der X- bzw. Y-Werte nach int
                    //um so in sehr engen Zellbereichen trotzdem einen gültigen CP ermitteln zu können
                    //-> bringt eigentlich auch nix, da so CP auf der gleichen Seite wie DCP1 ausgewählt werden....
                    //durch die neue Pfadberechnung wird allerdings nach einigen Anläufen die Zelle richtig abgetrennt...
                    bool isSeparated;
                    //Hier braucht nur eine Zuweisung eines Konturpunktes erfolgen, wenn ein Index ermittelt wurde.
                    //Sollte immer funktionieren, da immer der KP mit dem kleinsten Abstand ermittelt wird, ausser es wurden
                    //bereits alle KP geprüft, dann bleibt ind = -1
                    if (ind > -1)
                    {
                        pt2.X = contourPoints[ind].X;
                        pt2.Y = contourPoints[ind].Y;
                        testSepPoints(pt1, pt2, pt_node, out isSeparated);
                        if (isSeparated == true)
                        {
                            secondSCP.X = contourPoints[ind].X;
                            secondSCP.Y = contourPoints[ind].Y;
                            secondSCP.nodeDistance = actminDist;

                            //Prüfen ob die Verbindungslinie einen Zellkern oder Hintergrund schneidet
                            for (int k = 0; k < allCoresInCell.Count; k++)
                            {
                                HOperatorSet.GenRegionLine(out regionLine, secondSCP.Y, secondSCP.X, secondSCP.node.Y + rowOL, secondSCP.node.X + colOL);
                                HOperatorSet.Intersection(allCoresInCell[k].cellCore, regionLine, out regionIntersection);
                                HOperatorSet.AreaCenter(regionIntersection, out area, out rowCont, out colCont);
                                //Prüfen ob innenliegende Löcher durchlaufen werden
                                HOperatorSet.Intersection(cell.cellRegion, regionLine, out regionLineIntersection);
                                HOperatorSet.AreaCenter(regionLine, out area1, out rowCont1, out colCont1);
                                HOperatorSet.AreaCenter(regionLineIntersection, out area2, out rowCont2, out colCont2);

                                if ((area > 0) || (area2.I < (area1.I - 10)))
                                {
                                    //HOperatorSet.SetColor(Window, "red");
                                    //HOperatorSet.DispObj(regionLine, Window);
                                    intersection = true;
                                    secondSCP.X = -1;
                                    secondSCP.Y = -1;
                                    secondSCP.nodeDistance = 9999999;
                                    alreadyCheckedIndexes.Add(ind);
                                    break;
                                }
                            }
                            if (intersection == false)
                            {
                                isValid = true;
                            }
                        }
                        else
                        {
                            alreadyCheckedIndexes.Add(ind);
                        }
                    }
                }
            }
            return secondSCP;
        }

        //Den ersten gültigen Konturpunkt ermitteln, der dem mittleren Pfadpunkt am
        //nächsten liegt
        cellPix getCP1(nodesData midPoint, cellData cell, List<cellCoreData> validCellCores, List<DCP.DoublePoint> contourPoints)
        {
            int i;
            bool isValid = false;
            bool CP_AlreadyUsed = false;
            bool intersection = false;
            double minDist;
            double currentDist;
            HObject regionLine = null;
            HObject regionIntersection;
            HTuple rowCont, colCont, area;
            List<int> indexList = new List<int>();
            int index = -1;
            cellPix CP1 = new cellPix();

            CP1.x = -1; CP1.y = -1;
            int iterator = 0;
            while ((isValid == false) && (iterator <= 300))
            {
                intersection = false;
                iterator++;
                minDist = 999999999;
                //Hier noch durch Schleife mit allen Abständen laufen, da auch ein 2.ter oder 3.ter kleinster Abstand eines
                //bestimmten Nodes x noch kleiner sein kann, als der kleinste Abstand eines Nodes y
                for (i = 0; i < contourPoints.Count; i = i + 4)
                {
                    CP_AlreadyUsed = false;
                    //Falls der CP schon ausgewählt wurde, darf er nicht nochmal genommen werden
                    for (int l = 0; l < indexList.Count; l++)
                    {
                        if (i == indexList[l])
                            CP_AlreadyUsed = true;
                    }
                    currentDist = Math.Sqrt((contourPoints[i].X - (midPoint.node.X + colOL)) * (contourPoints[i].X - (midPoint.node.X + colOL)) + (contourPoints[i].Y - (midPoint.node.Y + rowOL)) * (contourPoints[i].Y - (midPoint.node.Y + rowOL)));
                    if ((currentDist < minDist) && (CP_AlreadyUsed == false))
                    {
                        minDist = currentDist;
                        CP1.x = contourPoints[i].X;
                        CP1.y = contourPoints[i].Y;
                        index = i;
                    }
                }
                indexList.Add(index);
                //Prüfen ob die Verbindungslinie des gefundenen nächsten CP zu dem mittleren Pfadpunkt (node) 
                //eine Zellkernregion schneidet
                for (int k = 0; k < allCoresInCell.Count; k++)
                {
                    HOperatorSet.GenRegionLine(out regionLine, CP1.y, CP1.x, midPoint.node.Y + rowOL, midPoint.node.X + colOL);
                    HOperatorSet.Intersection(allCoresInCell[k].cellCore, regionLine, out regionIntersection);
                    HOperatorSet.AreaCenter(regionIntersection, out area, out rowCont, out colCont);
                    if (area > 0)
                    {
                        intersection = true;
                        CP1.x = -1;
                        CP1.y = -1;
                    }
                }
                if (intersection == false)
                {
                    isValid = true;
                }
            }
            return CP1;
        }
        //Den zweiten gültigen Konturpunkt ermitteln, der dem mittleren Pfadpunkt am
        //nächsten liegt und auf der anderen Seite der DecisionRegion liegt wie CP1
        cellPix getCP2(nodesData midPoint, cellPix CP1, cellData cell, List<cellCoreData> validCellCores, List<DCP.DoublePoint> contourPoints, List<DCP.DoublePoint> innerContourPoints, HObject decisionRegion)
        {
            cellPix CP2 = new cellPix();
            int i, iterator, ind;
            bool isValid = false;
            bool CP_AlreadyUsed = false;
            bool intersection = false;
            bool alreadyUsed = false;
            bool isSeparated = false;
            double minDist = 0;
            double dist = 0;
            double currentDist;
            HObject regionLine = null;
            HObject regionIntersection, regionLineIntersection;
            HTuple rowCont, colCont, area, rowCont1, colCont1, area1;
            HTuple area2, rowCont2, colCont2;
            List<int> indexList = new List<int>();
            List<int> alreadyCheckedIndexes = new List<int>();
            int index = -1;

            DoublePoint pt1 = new DoublePoint();
            DoublePoint pt2 = new DoublePoint();
            DoublePoint pt_node = new DoublePoint();
            pt1.X = CP1.x;
            pt1.Y = CP1.y;
            pt_node.X = midPoint.node.X + colOL;
            pt_node.Y = midPoint.node.Y + rowOL;

            //Zuerst prüfen, ob ein innenliegender Konturpunkt in der Nähe des midPoints liegt
            CP2.x = -1; CP2.y = -1;
            intersection = false;
            iterator = 0;
            alreadyCheckedIndexes.Clear();
            ind = -1;
            double minimumDist = 50;
            while ((isValid == false) && (iterator <= innerContourPoints.Count / 10))
            {
                minimumDist = 50;
                iterator++;
                if (innerContourPoints.Count < 300)
                {
                    for (int k = 0; k < innerContourPoints.Count; k = k + 5)
                    {
                        alreadyUsed = false;
                        //Prüfen ob der aktuelle Konturpunkt schon mal genommen wurde
                        for (int l = 0; l < alreadyCheckedIndexes.Count; l++)
                        {
                            if (alreadyCheckedIndexes[l] == k)
                            {
                                alreadyUsed = true;
                                break;
                            }
                            else
                                alreadyUsed = false;
                        }
                        if (alreadyUsed == false)
                        {
                            dist = Math.Sqrt((innerContourPoints[k].X - (midPoint.node.X + colOL)) * (innerContourPoints[k].X - (midPoint.node.X + colOL)) + (innerContourPoints[k].Y - (midPoint.node.Y + rowOL)) * (innerContourPoints[k].Y - (midPoint.node.Y + rowOL)));
                            if (dist < minimumDist)
                            {
                                minimumDist = dist;
                                pt2.X = innerContourPoints[k].X;
                                pt2.Y = innerContourPoints[k].Y;
                                testSepPoints(pt1, pt2, pt_node, out isSeparated);
                                if (isSeparated == true)
                                {
                                    CP2.x = innerContourPoints[k].X;
                                    CP2.y = innerContourPoints[k].Y;
                                    ind = k;
                                }
                            }
                        }
                    }
                }
                else
                {
                    for (int k = 0; k < innerContourPoints.Count; k = k + 50)
                    {
                        alreadyUsed = false;
                        //Prüfen ob der aktuelle Konturpunkt schon mal genommen wurde
                        for (int l = 0; l < alreadyCheckedIndexes.Count; l++)
                        {
                            if (alreadyCheckedIndexes[l] == k)
                            {
                                alreadyUsed = true;
                                break;
                            }
                            else
                                alreadyUsed = false;
                        }
                        if (alreadyUsed == false)
                        {
                            dist = Math.Sqrt((innerContourPoints[k].X - (midPoint.node.X + colOL)) * (innerContourPoints[k].X - (midPoint.node.X + colOL)) + (innerContourPoints[k].Y - (midPoint.node.Y + rowOL)) * (innerContourPoints[k].Y - (midPoint.node.Y + rowOL)));
                            if (dist < minimumDist)
                            {
                                minimumDist = dist;
                                pt2.X = innerContourPoints[k].X;
                                pt2.Y = innerContourPoints[k].Y;
                                testSepPoints(pt1, pt2, pt_node, out isSeparated);
                                if (isSeparated == true)
                                {
                                    CP2.x = innerContourPoints[k].X;
                                    CP2.y = innerContourPoints[k].Y;
                                    ind = k;
                                }
                            }
                        }
                    }
                }
                //Prüfen ob die Verbindungslinie einen Zellkern oder Hintergrund schneidet
                for (int k = 0; k < allCoresInCell.Count; k++)
                {
                    HOperatorSet.GenRegionLine(out regionLine, CP2.y, CP2.x, midPoint.node.Y + rowOL, midPoint.node.X + colOL);
                    HOperatorSet.Intersection(allCoresInCell[k].cellCore, regionLine, out regionIntersection);
                    HOperatorSet.AreaCenter(regionIntersection, out area, out rowCont, out colCont);
                    //Prüfen ob innenliegende Löcher durchlaufen werden
                    HOperatorSet.Intersection(cell.cellRegion, regionLine, out regionLineIntersection);
                    HOperatorSet.AreaCenter(regionLine, out area1, out rowCont1, out colCont1);
                    HOperatorSet.AreaCenter(regionLineIntersection, out area2, out rowCont2, out colCont2);

                    if ((area > 0) || (area2.I < (area1.I - 10)))
                    {
                        intersection = true;
                        CP2.x = -1;
                        CP2.y = -1;
                        alreadyCheckedIndexes.Add(ind);
                    }
                }
                if (intersection == false)
                {
                    isValid = true;
                }
            }
            iterator = 0;
            if ((CP2.x == -1) && (CP2.y == -1))
            {
                while ((isValid == false) && (iterator <= 100))
                {
                    iterator++;
                    minDist = 999999999;
                    intersection = false;
                    //Hier noch durch Schleife mit allen Abständen laufen, da auch ein 2.ter oder 3.ter kleinster Abstand eines
                    //bestimmten Nodes x noch kleiner sein kann, als der kleinste Abstand eines Nodes y
                    for (i = 0; i < contourPoints.Count; i = i + 5)
                    {
                        CP_AlreadyUsed = false;
                        //Falls der CP schon ausgewählt wurde, darf er nicht nochmal genommen werden
                        for (int l = 0; l < indexList.Count; l++)
                        {
                            if (i == indexList[l])
                                CP_AlreadyUsed = true;
                        }
                        currentDist = Math.Sqrt((contourPoints[i].X - (midPoint.node.X + colOL)) * (contourPoints[i].X - (midPoint.node.X + colOL)) + (contourPoints[i].Y - (midPoint.node.Y + rowOL)) * (contourPoints[i].Y - (midPoint.node.Y + rowOL)));
                        if ((currentDist < minDist) && (CP_AlreadyUsed == false) && (contourPoints[i].X != CP1.x) && (contourPoints[i].Y != CP1.y))
                        {
                            pt2.X = contourPoints[i].X;
                            pt2.Y = contourPoints[i].Y;
                            testSepPoints(pt1, pt2, pt_node, out isSeparated);
                            if (isSeparated == true)
                            {
                                minDist = currentDist;
                                CP2.x = contourPoints[i].X;
                                CP2.y = contourPoints[i].Y;
                                index = i;
                            }
                        }
                    }
                    indexList.Add(index);
                    //Prüfen ob die Verbindungslinie des gefundenen nächsten CP zu dem mittleren Pfadpunkt (node) 
                    //eine Zellkernregion schneidet
                    for (int k = 0; k < allCoresInCell.Count; k++)
                    {
                        HOperatorSet.GenRegionLine(out regionLine, CP2.y, CP2.x, midPoint.node.Y + rowOL, midPoint.node.X + colOL);
                        HOperatorSet.Intersection(allCoresInCell[k].cellCore, regionLine, out regionIntersection);
                        HOperatorSet.AreaCenter(regionIntersection, out area, out rowCont, out colCont);
                        if (area > 0)
                        {
                            intersection = true;
                            CP2.x = -1;
                            CP2.y = -1;
                        }
                    }
                    if (intersection == false)
                    {
                        isValid = true;
                    }
                }
            }
            return CP2;
        }
    }
    public static class HalconFunctions
    {
        public static HObject getCellsAsRegions(HObject Img, int MinCellArea)
        {
            // Local iconic variables 
            HObject ho_GrayImage;
            HObject ho_Region, ho_RegionDilation, ho_RegionErosion;
            HObject ho_RegionFillUp, ho_ConnectedRegions, ho_SelectedRegions;

            // Initialize local and output iconic variables 
            HOperatorSet.GenEmptyObj(out ho_GrayImage);
            HOperatorSet.GenEmptyObj(out ho_Region);
            HOperatorSet.GenEmptyObj(out ho_RegionDilation);
            HOperatorSet.GenEmptyObj(out ho_RegionErosion);
            HOperatorSet.GenEmptyObj(out ho_RegionFillUp);
            HOperatorSet.GenEmptyObj(out ho_ConnectedRegions);
            HOperatorSet.GenEmptyObj(out ho_SelectedRegions);

            HOperatorSet.Rgb1ToGray(Img, out ho_GrayImage);
            ho_Region.Dispose();
            HOperatorSet.Threshold(ho_GrayImage, out ho_Region, 1, 255);
            ho_RegionDilation.Dispose();
            HOperatorSet.DilationCircle(ho_Region, out ho_RegionDilation, 1);
            ho_RegionErosion.Dispose();
            HOperatorSet.ErosionCircle(ho_RegionDilation, out ho_RegionErosion, 1);
            ho_RegionFillUp.Dispose();
            //Fill Up Parametrisieren!!!!!!!!!!
            HOperatorSet.FillUpShape(ho_RegionErosion, out ho_RegionFillUp, "area", 1, 50);
            ho_ConnectedRegions.Dispose();
            HOperatorSet.Connection(ho_RegionFillUp, out ho_ConnectedRegions);
            ho_SelectedRegions.Dispose();
            HOperatorSet.SelectShape(ho_ConnectedRegions, out ho_SelectedRegions, "area", "and", MinCellArea, 9999999);//minarea:250

            ho_GrayImage.Dispose();
            ho_Region.Dispose();
            ho_RegionDilation.Dispose();
            ho_RegionErosion.Dispose();
            ho_RegionFillUp.Dispose();
            ho_ConnectedRegions.Dispose();

            return ho_SelectedRegions;
        }
        public static List<cellData> assignCellHolesToCellDataList(List<cellData> cells, HObject cellsHoles)
        {
            HTuple area, row, col, holeCount;
            HObject unioncellsHoles, cellHoleRegion, connectedCellHoleRegion, selectedHole, filledCellRegion;

            List<cellData> newCells = new List<cellData>();

            try
            {
                if (cellsHoles != null)
                {
                    HOperatorSet.Union1(cellsHoles, out unioncellsHoles);
                    //Prüfen welche Löcher zu der aktuellen Zelle gehören
                    for (int i = 0; i < cells.Count; i++)
                    {
                        //Neue Zelle erstellen
                        cellData newCell = new cellData();
                        newCell.cellContour = cells[i].cellContour;
                        newCell.cellRegion = cells[i].cellRegion;
                        newCell.CoreInfo = cells[i].CoreInfo;
                        newCell.isCluster = cells[i].isCluster;
                        newCell.nr = cells[i].nr;
                        newCell.wasBarbelCell = cells[i].wasBarbelCell;
                        newCell.statistics = cells[i].statistics;

                        HOperatorSet.FillUp(cells[i].cellRegion, out filledCellRegion);
                        HOperatorSet.Intersection(filledCellRegion, unioncellsHoles, out cellHoleRegion);
                        //Prüfen ob es Löcher in der aktuellen Zelle gibt indem die Fläche > 0 Pix überprüft wird
                        HOperatorSet.AreaCenter(cellHoleRegion, out area, out row, out col);
                        if ((area.Length > 0) && (area.D > 0))
                        {
                            //Bereichsegmentierung der Zelllochregion, falls es sich um mehrere flächenmäßig getrennte Löcher handelt
                            HOperatorSet.Connection(cellHoleRegion, out connectedCellHoleRegion);
                            //Anzahl unabh. Löcher bestimmen
                            HOperatorSet.CountObj(connectedCellHoleRegion, out holeCount);
                            HObject[] cellHoles = new HObject[holeCount];
                            for (int j = 0; j < holeCount; j++)
                            {
                                HOperatorSet.SelectObj(connectedCellHoleRegion, out selectedHole, j + 1);
                                cellHoles[j] = selectedHole;
                            }
                            newCell.cellHoles = cellHoles;
                        }
                        newCells.Add(newCell);
                    }

                    return newCells;
                }
                else
                    return cells;
            }
            catch { return newCells; }
        }
        public static List<double> calcCellsSaturation(HObject cellRegions, TImage image, out TImage img_sat)
        {
            TImage img_Saturation = imageWorker.calcRGBImgSaturation(image);

            //(Bitmap((img_Saturation.Image).Clone())).Save("C:\\Img_Sat.bmp");

            img_sat = img_Saturation;

            List<double> cellSaturation = new List<double>();

            HObject img_Saturation_HAL, img_Saturation_HAL_Reduced, unionCellRegions;
            HObject imageR, imageG, imageB, imageH, imageS, imageV;
            HObject cellSaturationRegions, connectedSaturationRegions, objectSelected;
            HTuple numberRegions, meanIntensity, deviation;

            HalconDotNet.HOperatorSet.GenImageInterleaved(out img_Saturation_HAL, img_Saturation.firstPixel, "bgr",
                            img_Saturation.Width, img_Saturation.Height, 0, "byte",
                            0, 0, 0, 0, -1, 0);

            HOperatorSet.Union1(cellRegions, out unionCellRegions);
            HOperatorSet.ReduceDomain(img_Saturation_HAL, unionCellRegions, out img_Saturation_HAL_Reduced);
            HOperatorSet.Decompose3(img_Saturation_HAL_Reduced, out imageR, out imageG, out imageB);
            HOperatorSet.TransFromRgb(imageR, imageG, imageB, out imageH, out imageS, out imageV, "hsv");
            HOperatorSet.Threshold(imageS, out cellSaturationRegions, 0, 255);
            HOperatorSet.Connection(cellSaturationRegions, out connectedSaturationRegions);
            HOperatorSet.CountObj(connectedSaturationRegions, out numberRegions);

            //HOperatorSet.ReduceDomain(img_Saturation_HAL, cellRegions, out cellsSaturation);

            for (int i = 0; i < numberRegions.I; i++)
            {
                HOperatorSet.SelectObj(connectedSaturationRegions, out objectSelected, i + 1);
                HOperatorSet.Intensity(objectSelected, imageS, out meanIntensity, out deviation);
                cellSaturation.Add(meanIntensity.D);
            }
            return cellSaturation;
        }
        //Sättigung einer einzelnen Zelle berechnen
        public static double calcCellSaturation(HObject cellRegion, String image)
        {
            TImage img_Saturation = imageWorker.calcRGBImgSaturation(new TImage(image));

            List<double> cellSaturation = new List<double>();

            HObject img_Saturation_HAL, img_Saturation_HAL_Reduced, unionCellRegions;
            HObject imageR, imageG, imageB, imageH, imageS, imageV;
            HObject cellSaturationRegions;
            HTuple meanIntensity, deviation;

            HalconDotNet.HOperatorSet.GenImageInterleaved(out img_Saturation_HAL, img_Saturation.firstPixel, "bgr",
                                                          img_Saturation.Width, img_Saturation.Height, 0, "byte",
                                                          0, 0, 0, 0, -1, 0);

            HOperatorSet.Union1(cellRegion, out unionCellRegions);
            HOperatorSet.ReduceDomain(img_Saturation_HAL, unionCellRegions, out img_Saturation_HAL_Reduced);
            HOperatorSet.Decompose3(img_Saturation_HAL_Reduced, out imageR, out imageG, out imageB);
            HOperatorSet.TransFromRgb(imageR, imageG, imageB, out imageH, out imageS, out imageV, "hsv");
            HOperatorSet.Threshold(imageS, out cellSaturationRegions, 0, 255);
            HOperatorSet.Intensity(cellSaturationRegions, imageS, out meanIntensity, out deviation);

            return meanIntensity.D;
        }
        //Sättigung einer einzelnen Zelle berechnen
        public static void calcCellSaturation(HObject cellRegion, HObject img_Saturation_HAL, out HTuple meanIntensity, out HTuple deviation)
        {
            List<double> cellSaturation = new List<double>();

            HObject img_Saturation_HAL_Reduced, unionCellRegions;
            HObject imageR, imageG, imageB, imageH, imageS, imageV;
            HObject cellSaturationRegions;

            //HalconDotNet.HOperatorSet.GenImageInterleaved(out img_Saturation_HAL, img_Saturation.firstPixel, "bgr",
            //                                              img_Saturation.Width, img_Saturation.Height, 0, "byte",
            //                                              0, 0, 0, 0, -1, 0);

            HOperatorSet.Union1(cellRegion, out unionCellRegions);
            HOperatorSet.ReduceDomain(img_Saturation_HAL, unionCellRegions, out img_Saturation_HAL_Reduced);
            HOperatorSet.Decompose3(img_Saturation_HAL_Reduced, out imageR, out imageG, out imageB);
            HOperatorSet.TransFromRgb(imageR, imageG, imageB, out imageH, out imageS, out imageV, "hsv");
            HOperatorSet.Threshold(imageS, out cellSaturationRegions, 0, 255);
            HOperatorSet.Intensity(cellSaturationRegions, imageS, out meanIntensity, out deviation);
        }
        //Randzellen eliminieren

        /// <summary>
        /// Methode zum eleminieren von Randzellen die nicht vollständig im Bild enthalten sind und bestimmte Kriterien nicht erfüllen 
        /// </summary>
        /// <param name="cells"></param>
        /// <param name="noIgnorationMinCellArea">Zellfläche ab der die Zelle in keinem Fall ignoriert wird (Wahrscheinlichkeit hoch fü Cluster)</param>
        /// <param name="BorderContactRatioValue">Verhältnis von Zellkonturlänge zur Schnittmenge mit dem Bildrand</param>
        /// <param name="width"></param>
        /// <param name="height"></param>
        /// <param name="window"></param>
        /// <returns></returns>
        public static List<cellData> eliminateBorderCells(List<cellData> cells, int noIgnorationMinCellArea, double BorderContactRatioValue, int width, int height, HTuple window)
        {
            HObject region1, region2, region3, region4, regionIntersection;
            HObject region12, region123, region1234;
            HTuple areaCell, rowCell, colCell, areaIntersection, rowIntersection, colIntersection;
            HTuple cellContLength, compactnessCell, circularityCell;
            List<cellData> newCells = new List<cellData>();
            double BorderContactRatio;

            HOperatorSet.GenRegionLine(out region1, 0, 0, 0, width - 1);
            HOperatorSet.GenRegionLine(out region2, 0, width - 1, height - 1, width - 1);
            HOperatorSet.GenRegionLine(out region3, height - 1, width - 1, height - 1, 0);
            HOperatorSet.GenRegionLine(out region4, 1, 1, height - 1, 1);

            HOperatorSet.Union2(region1, region2, out region12);
            HOperatorSet.Union2(region12, region3, out region123);
            HOperatorSet.Union2(region123, region4, out region1234);

            int validcellCounter = 0;
            for (int i = 0; i < cells.Count; i++)
            {
                HOperatorSet.Intersection(region1234, cells[i].cellRegion, out regionIntersection);
                HOperatorSet.AreaCenter(regionIntersection, out areaIntersection, out rowIntersection, out colIntersection);
                HOperatorSet.AreaCenter(cells[i].cellRegion, out areaCell, out rowCell, out colCell);
                HOperatorSet.Contlength(cells[i].cellRegion, out cellContLength);
                //Prüfen ob die Zellregion den Bildrand schneidet
                if (areaIntersection.D > 0)
                {
                    //Wenn ja als nächstes prüfen ob die Zellfläche > X Pix ist (hier X = 10.000 Pixel)
                    if (areaCell.D > noIgnorationMinCellArea)
                    {
                        //Zelle wird nicht ignoriert da sie groß ist und die Wahrscheinlichkeit für einen Cluster groß ist
                        //!!!!!!!!!!EVTL diese Regel verwerfen wenn man sowieso nach der Clustertrennung erst die Randzellen
                        //behandlung durchführt, da an dieser Stelle dann die Cluster aufgespalten sein sollten und demnach
                        //eine große Einzelzelle den Rand schneidet. In diesem Fall dann normal weiterverfahren....
                        validcellCounter++;
                        cellData newCell = new cellData();
                        newCell.cellContour = cells[i].cellContour;
                        newCell.cellHoles = cells[i].cellHoles;
                        newCell.cellRegion = cells[i].cellRegion;
                        newCell.CoreInfo = cells[i].CoreInfo;
                        newCell.isCluster = cells[i].isCluster;
                        newCell.wasBarbelCell = cells[i].wasBarbelCell;
                        newCell.nr = validcellCounter;
                        newCell.statistics = cells[i].statistics;

                        newCells.Add(newCell);
                    }
                    else
                    {
                        //Verhältnis der Zellkonturlänge zur Schnittmenge mit dem Bildrand bestimmen
                        BorderContactRatio = cellContLength / areaIntersection.D;
                        //Prüfen ob BorderContactRatio > y (y = 10)
                        if (BorderContactRatio > BorderContactRatioValue)
                        {
                            //Wenn die Kompaktheit der Zelle > 10 UND die Kreisförmigkeit < 0.1 UND Fläche < 1500 -> Wahrscheinlichkeit für Zellausläufer hoch -> Ignorieren
                            HOperatorSet.Compactness(cells[i].cellRegion, out compactnessCell);
                            HOperatorSet.Circularity(cells[i].cellRegion, out circularityCell);
                            if ((compactnessCell > 10 || circularityCell < 0.1) && areaCell < 1500)
                            {
                                //Ignorieren
                            }
                            else
                            {
                                //nicht ignorieren
                                validcellCounter++;
                                cellData newCell = new cellData();
                                newCell.cellContour = cells[i].cellContour;
                                newCell.cellHoles = cells[i].cellHoles;
                                newCell.cellRegion = cells[i].cellRegion;
                                newCell.CoreInfo = cells[i].CoreInfo;
                                newCell.isCluster = cells[i].isCluster;
                                newCell.wasBarbelCell = cells[i].wasBarbelCell;
                                newCell.nr = validcellCounter;
                                newCell.statistics = cells[i].statistics;

                                newCells.Add(newCell);
                            }
                        }
                        else
                        {
                            //Wenn BorderContactRatio < X -> der Anteil der Zelle der aus dem Bild raus läuft ist zu hoch, Zelle wird ignoriert
                        }
                    }
                }
                else
                {
                    //Nicht ignorieren
                    validcellCounter++;
                    cellData newCell = new cellData();
                    newCell.cellContour = cells[i].cellContour;
                    newCell.cellHoles = cells[i].cellHoles;
                    newCell.cellRegion = cells[i].cellRegion;
                    newCell.CoreInfo = cells[i].CoreInfo;
                    newCell.isCluster = cells[i].isCluster;
                    newCell.nr = validcellCounter;
                    newCell.wasBarbelCell = cells[i].wasBarbelCell;
                    newCell.statistics = cells[i].statistics;

                    newCells.Add(newCell);
                }
            }
            // 2. Regel: 
            return newCells;
        }
    }

    public static class cellDataFromGeoObjects
    {
        public static List<cellData> generateCellDataFromGeoObjects(List<GeoObject> geoObjects)
        {
            HTuple rows, cols;
            HObject newCellRegion;
            List<cellData> newCellDataList = new List<cellData>();
            List<GeoObject> cellObjects = new List<GeoObject>();
            List<GeoObject> coreObjects = new List<GeoObject>();
            int counter = 0;

            try
            {
                //Kerne und Zellen in seperate Listen auslagern um die nachfolgende Schleife zu beschleunigen
                for (int i = 0; i < geoObjects.Count; i++)
                {
                    if (geoObjects[i].Layer == 2)
                    {
                        coreObjects.Add(geoObjects[i]);
                    }
                    else if (geoObjects[i].Layer == 1)
                    {
                        cellObjects.Add(geoObjects[i]);
                    }
                }

                for (int i = 0; i < geoObjects.Count; i++)
                {
                    counter++;
                    //Zellinformationen neu berechnen lassen
                    //->Prüfen ob vorhandene Kerne zu diesem Polygon gehören
                    //->Zellstatistiken neu berechnen
                    HOperatorSet.TupleGenConst(geoObjects[i].EditPoints.Count, 0, out rows);
                    HOperatorSet.TupleGenConst(geoObjects[i].EditPoints.Count, 0, out cols);

                    for (int k = 0; k < cellObjects[i].EditPoints.Count; k++)
                    {
                        rows[k] = cellObjects[i].EditPoints[k].Y;
                        cols[k] = cellObjects[i].EditPoints[k].X;
                    }
                    //Halcon Region aus Polygon-Stützpunkten erzeugen
                    HOperatorSet.GenRegionPolygonFilled(out newCellRegion, rows, cols);

                    cellData newCell = new cellData();
                    newCell.cellRegion = newCellRegion;
                    newCell.nr = counter;
                    //Prüfen welche Kerne innerhalb des aktuellen Polygons liegen und der neuen Zelle zuweisen
                    //Dazu jeden Kern in eine Halcon-Region umwandeln und einen Schnitttest mit der Zellregion durchführen
                    newCell.CoreInfo = CoresInsidePoly(newCellRegion, coreObjects);
                    newCellDataList.Add(newCell);
                    //Neuen Zellstatistikdatensatz hinzufügen
                    //newCell = calcCellStatistics(newCell, checkBox_CalcSaturation.Checked, img_Saturation_HAL);
                    ////Zellvitalität/Status zuweisen
                    //if (cellObjects[i].Layer == 1)
                    //    newCell.isAlive = true;
                    //if (cellObjects[i].Layer == 4)
                    //{
                    //    newCell.isAlive = false;
                    //}
                    //if (cellObjects[i].Layer == 5)
                    //{
                    //    newCell.wasBarbelCell = true;
                    //}
                    ////Da sich die Zellmerkmale bei einer Bearbeitung ändern könnte, wird die Zellvitalität
                    ////hier noch mal neu berechnet
                    //newCell = cellAnalyser.analyseCellVitality(newCell, comboBox_feature1.Text, comboBox_feature2.Text, comboBox_feature3.Text,
                    //                                           Convert.ToDouble(textBox_feature1_min.Text), Convert.ToDouble(textBox_feature1_max.Text),
                    //                                           Convert.ToDouble(textBox_feature2_min.Text), Convert.ToDouble(textBox_feature2_max.Text),
                    //                                           Convert.ToDouble(textBox_feature3_min.Text), Convert.ToDouble(textBox_feature3_max.Text));
                    ////GGF. Layer neu setzten wenn sich der Vitalitätsstatus einer Zelle geändert hat
                    //if (newCell.isAlive == true)
                    //{
                    //    if (newCell.wasBarbelCell == true)
                    //        cellObjects[i].Layer = 5;
                    //    else
                    //        cellObjects[i].Layer = 1;
                    //}
                    //else
                    //{
                    //    if (newCell.wasBarbelCell == true)
                    //        cellObjects[i].Layer = 5;
                    //    else
                    //        cellObjects[i].Layer = 4;
                    //}
                }
                return newCellDataList;
            }
            catch (System.Exception ex)
            {
                MessageBox.Show("Fehler in Methode generateCellDataFromGeoObjects: "+ex.Message);
                return newCellDataList;
            }
        }
        public static List<cellCoreData> CoresInsidePoly(HObject cell, List<GeoObject> polygons)
        {
            HObject newCoreRegion, regionIntersection;
            HTuple rows, cols, area, rowInter, colInter;

            List<cellCoreData> cellCores = new List<cellCoreData>();

            for (int i = 0; i < polygons.Count; i++)
            {
                HOperatorSet.TupleGenConst(polygons[i].EditPoints.Count, 0, out rows);
                HOperatorSet.TupleGenConst(polygons[i].EditPoints.Count, 0, out cols);

                for (int k = 0; k < polygons[i].EditPoints.Count; k++)
                {
                    rows[k] = polygons[i].EditPoints[k].Y;
                    cols[k] = polygons[i].EditPoints[k].X;
                }
                //Halcon Region aus Polygon-Stützpunkten erzeugen
                HOperatorSet.GenRegionPolygonFilled(out newCoreRegion, rows, cols);

                HOperatorSet.Intersection(cell, newCoreRegion, out regionIntersection);
                HOperatorSet.AreaCenter(regionIntersection, out area, out rowInter, out colInter);
                //Prüfen ob eine Schnittmenge zwischen Kern und Zelle besteht
                if (area.D > 0)
                {
                    //Wenn eine Schnittmenge zwischen Kern und Zelle besteht, den Kern der Kernliste hinzufügen.
                    cellCoreData newCore = new cellCoreData();
                    newCore.cellCore = newCoreRegion;
                    cellCores.Add(newCore);
                    polygons.RemoveAt(i);
                    i--;
                }
            }
            return cellCores;
        }
    }

    public static class cellAnalyser
    {
        public static List<cellData> analyseCellVitality(List<cellData> cells, String feature1, String feature2, String feature3,
                                                   double feature1_min, double feature1_max,
                                                   double feature2_min, double feature2_max,
                                                   double feature3_min, double feature3_max)
        {
            bool feature1_ok, feature2_ok, feature3_ok;
            HTuple row, col, featureVal;

            try
            {
                for (int i = 0; i < cells.Count; i++)
                {
                    feature1_ok = false;
                    feature2_ok = false;
                    feature3_ok = false;
                    switch (feature1)
                    {
                        case "nothing": feature1_ok = true;
                            break;
                        case "area": HOperatorSet.AreaCenter(cells[i].cellRegion, out featureVal, out row, out col);
                            if ((featureVal >= feature1_min) && (featureVal <= feature1_max))
                                feature1_ok = true;
                            else
                                feature1_ok = false;
                            break;
                        case "circularity": HOperatorSet.Circularity(cells[i].cellRegion, out featureVal);
                            if ((featureVal >= feature1_min) && (featureVal <= feature1_max))
                                feature1_ok = true;
                            else
                                feature1_ok = false;
                            break;
                        case "compactness": HOperatorSet.Compactness(cells[i].cellRegion, out featureVal);
                            if ((featureVal >= feature1_min) && (featureVal <= feature1_max))
                                feature1_ok = true;
                            else
                                feature1_ok = false;
                            break;
                        case "contlength": HOperatorSet.Contlength(cells[i].cellRegion, out featureVal);
                            if ((featureVal >= feature1_min) && (featureVal <= feature1_max))
                                feature1_ok = true;
                            else
                                feature1_ok = false;
                            break;
                        case "convexity": HOperatorSet.Convexity(cells[i].cellRegion, out featureVal);
                            if ((featureVal >= feature1_min) && (featureVal <= feature1_max))
                                feature1_ok = true;
                            else
                                feature1_ok = false;
                            break;
                        case "orientation": HOperatorSet.OrientationRegion(cells[i].cellRegion, out featureVal);
                            if ((featureVal >= feature1_min) && (featureVal <= feature1_max))
                                feature1_ok = true;
                            else
                                feature1_ok = false;
                            break;
                        default: feature1_ok = false;
                            break;
                    }

                    switch (feature2)
                    {
                        case "nothing": feature2_ok = true;
                            break;
                        case "area": HOperatorSet.AreaCenter(cells[i].cellRegion, out featureVal, out row, out col);
                            if ((featureVal >= feature2_min) && (featureVal <= feature2_max))
                                feature2_ok = true;
                            else
                                feature2_ok = false;
                            break;
                        case "circularity": HOperatorSet.Circularity(cells[i].cellRegion, out featureVal);
                            if ((featureVal >= feature2_min) && (featureVal <= feature2_max))
                                feature2_ok = true;
                            else
                                feature2_ok = false;
                            break;
                        case "compactness": HOperatorSet.Compactness(cells[i].cellRegion, out featureVal);
                            if ((featureVal >= feature2_min) && (featureVal <= feature2_max))
                                feature2_ok = true;
                            else
                                feature2_ok = false;
                            break;
                        case "contlength": HOperatorSet.Contlength(cells[i].cellRegion, out featureVal);
                            if ((featureVal >= feature2_min) && (featureVal <= feature2_max))
                                feature2_ok = true;
                            else
                                feature2_ok = false;
                            break;
                        case "convexity": HOperatorSet.Convexity(cells[i].cellRegion, out featureVal);
                            if ((featureVal >= feature2_min) && (featureVal <= feature2_max))
                                feature2_ok = true;
                            else
                                feature2_ok = false;
                            break;
                        case "orientation": HOperatorSet.OrientationRegion(cells[i].cellRegion, out featureVal);
                            if ((featureVal >= feature2_min) && (featureVal <= feature2_max))
                                feature2_ok = true;
                            else
                                feature2_ok = false;
                            break;
                        default: feature2_ok = false;
                            break;
                    }

                    switch (feature3)
                    {
                        case "nothing": feature3_ok = true;
                            break;
                        case "area": HOperatorSet.AreaCenter(cells[i].cellRegion, out featureVal, out row, out col);
                            if ((featureVal >= feature3_min) && (featureVal <= feature3_max))
                                feature3_ok = true;
                            else
                                feature3_ok = false;
                            break;
                        case "circularity": HOperatorSet.Circularity(cells[i].cellRegion, out featureVal);
                            if ((featureVal >= feature3_min) && (featureVal <= feature3_max))
                                feature3_ok = true;
                            else
                                feature3_ok = false;
                            break;
                        case "compactness": HOperatorSet.Compactness(cells[i].cellRegion, out featureVal);
                            if ((featureVal >= feature3_min) && (featureVal <= feature3_max))
                                feature3_ok = true;
                            else
                                feature3_ok = false;
                            break;
                        case "contlength": HOperatorSet.Contlength(cells[i].cellRegion, out featureVal);
                            if ((featureVal >= feature3_min) && (featureVal <= feature3_max))
                                feature3_ok = true;
                            else
                                feature3_ok = false;
                            break;
                        case "convexity": HOperatorSet.Convexity(cells[i].cellRegion, out featureVal);
                            if ((featureVal >= feature3_min) && (featureVal <= feature3_max))
                                feature3_ok = true;
                            else
                                feature3_ok = false;
                            break;
                        case "orientation": HOperatorSet.OrientationRegion(cells[i].cellRegion, out featureVal);
                            if ((featureVal >= feature3_min) && (featureVal <= feature3_max))
                                feature3_ok = true;
                            else
                                feature3_ok = false;
                            break;
                        default: feature3_ok = false;
                            break;
                    }

                    //Wenn die eingestellten Features mit den eingestellten Grenzwerten erfüllt wurden -> lebend, ansonsten eine tote Zelle
                    if ((feature1_ok == true) && (feature2_ok == true) && (feature3_ok == true))
                        cells[i].isAlive = false;
                    else
                        cells[i].isAlive = true;
                }
                return cells;
            }
            catch (System.Exception ex)
            {
                MessageBox.Show(ex.Message);
                return cells;
            }
        }
        public static cellData analyseCellVitality(cellData cell, String feature1, String feature2, String feature3,
                                                   double feature1_min, double feature1_max,
                                                   double feature2_min, double feature2_max,
                                                   double feature3_min, double feature3_max)
        {
            bool feature1_ok, feature2_ok, feature3_ok;
            HTuple row, col, featureVal;
            try
            {
                switch (feature1)
                {
                    case "nothing": feature1_ok = true;
                        break;
                    case "area": HOperatorSet.AreaCenter(cell.cellRegion, out featureVal, out row, out col);
                        if ((featureVal >= feature1_min) && (featureVal <= feature1_max))
                            feature1_ok = true;
                        else
                            feature1_ok = false;
                        break;
                    case "circularity": HOperatorSet.Circularity(cell.cellRegion, out featureVal);
                        if ((featureVal >= feature1_min) && (featureVal <= feature1_max))
                            feature1_ok = true;
                        else
                            feature1_ok = false;
                        break;
                    case "compactness": HOperatorSet.Compactness(cell.cellRegion, out featureVal);
                        if ((featureVal >= feature1_min) && (featureVal <= feature1_max))
                            feature1_ok = true;
                        else
                            feature1_ok = false;
                        break;
                    case "contlength": HOperatorSet.Contlength(cell.cellRegion, out featureVal);
                        if ((featureVal >= feature1_min) && (featureVal <= feature1_max))
                            feature1_ok = true;
                        else
                            feature1_ok = false;
                        break;
                    case "convexity": HOperatorSet.Convexity(cell.cellRegion, out featureVal);
                        if ((featureVal >= feature1_min) && (featureVal <= feature1_max))
                            feature1_ok = true;
                        else
                            feature1_ok = false;
                        break;
                    case "orientation": HOperatorSet.OrientationRegion(cell.cellRegion, out featureVal);
                        if ((featureVal >= feature1_min) && (featureVal <= feature1_max))
                            feature1_ok = true;
                        else
                            feature1_ok = false;
                        break;
                    default: feature1_ok = false;
                        break;
                }

                switch (feature2)
                {
                    case "nothing": feature2_ok = true;
                        break;
                    case "area": HOperatorSet.AreaCenter(cell.cellRegion, out featureVal, out row, out col);
                        if ((featureVal >= feature2_min) && (featureVal <= feature2_max))
                            feature2_ok = true;
                        else
                            feature2_ok = false;
                        break;
                    case "circularity": HOperatorSet.Circularity(cell.cellRegion, out featureVal);
                        if ((featureVal >= feature2_min) && (featureVal <= feature2_max))
                            feature2_ok = true;
                        else
                            feature2_ok = false;
                        break;
                    case "compactness": HOperatorSet.Compactness(cell.cellRegion, out featureVal);
                        if ((featureVal >= feature2_min) && (featureVal <= feature2_max))
                            feature2_ok = true;
                        else
                            feature2_ok = false;
                        break;
                    case "contlength": HOperatorSet.Contlength(cell.cellRegion, out featureVal);
                        if ((featureVal >= feature2_min) && (featureVal <= feature2_max))
                            feature2_ok = true;
                        else
                            feature2_ok = false;
                        break;
                    case "convexity": HOperatorSet.Convexity(cell.cellRegion, out featureVal);
                        if ((featureVal >= feature2_min) && (featureVal <= feature2_max))
                            feature2_ok = true;
                        else
                            feature2_ok = false;
                        break;
                    case "orientation": HOperatorSet.OrientationRegion(cell.cellRegion, out featureVal);
                        if ((featureVal >= feature2_min) && (featureVal <= feature2_max))
                            feature2_ok = true;
                        else
                            feature2_ok = false;
                        break;
                    default: feature2_ok = false;
                        break;
                }

                switch (feature3)
                {
                    case "nothing": feature3_ok = true;
                        break;
                    case "area": HOperatorSet.AreaCenter(cell.cellRegion, out featureVal, out row, out col);
                        if ((featureVal >= feature3_min) && (featureVal <= feature3_max))
                            feature3_ok = true;
                        else
                            feature3_ok = false;
                        break;
                    case "circularity": HOperatorSet.Circularity(cell.cellRegion, out featureVal);
                        if ((featureVal >= feature3_min) && (featureVal <= feature3_max))
                            feature3_ok = true;
                        else
                            feature3_ok = false;
                        break;
                    case "compactness": HOperatorSet.Compactness(cell.cellRegion, out featureVal);
                        if ((featureVal >= feature3_min) && (featureVal <= feature3_max))
                            feature3_ok = true;
                        else
                            feature3_ok = false;
                        break;
                    case "contlength": HOperatorSet.Contlength(cell.cellRegion, out featureVal);
                        if ((featureVal >= feature3_min) && (featureVal <= feature3_max))
                            feature3_ok = true;
                        else
                            feature3_ok = false;
                        break;
                    case "convexity": HOperatorSet.Convexity(cell.cellRegion, out featureVal);
                        if ((featureVal >= feature3_min) && (featureVal <= feature3_max))
                            feature3_ok = true;
                        else
                            feature3_ok = false;
                        break;
                    case "orientation": HOperatorSet.OrientationRegion(cell.cellRegion, out featureVal);
                        if ((featureVal >= feature3_min) && (featureVal <= feature3_max))
                            feature3_ok = true;
                        else
                            feature3_ok = false;
                        break;
                    default: feature3_ok = false;
                        break;
                }

                //Wenn die Fläche < als die eingestellte Grenzfläche und die Kreisförmitkeit > als die eingestellte Grenzkreisförmigkeit ist
                //handelt es sich um eine tote, andernfalls um eine lebende Zelle
                if ((feature1_ok == true) && (feature2_ok == true) && (feature3_ok == true))
                    cell.isAlive = false;
                else
                    cell.isAlive = true;
                return cell;
            }
            catch (System.Exception ex)
            {
                MessageBox.Show("Fehler in Methode analyseCellVitality: "+ ex.Message);
                return cell;
            }
        }
        public static void getCellAnalysisResults(List<cellData> cells, List<GeoObject> geoObjects, double calibrationFactor, int width, int height,
                                                  out int totalCellCount, out int aliveCellCount, out int deadCellCount,
                                                  out double meanSaturation, out double averageCellArea, out String averageCellAreaUnit,
                                                  out double cellDensity, out String cellDensityUnit)
        {
            //Zellfläche
            HTuple area, row111, col111;
            double cellArea = 0;

            totalCellCount = 0;
            aliveCellCount = 0;
            deadCellCount = 0;
            meanSaturation = 0;
            averageCellArea = 0;
            cellDensity = 0;
            averageCellAreaUnit = "";
            cellDensityUnit = "";

            //Gesamtzellfläche berechnen
            for (int i = 0; i < cells.Count; i++)
            {
                HOperatorSet.AreaCenter(cells[i].cellRegion, out area, out row111, out col111);
                cellArea = cellArea + area.D;
            }
            for (int i = 0; i < cells.Count; i++)
            {
                HOperatorSet.AreaCenter(cells[i].cellRegion, out area, out row111, out col111);
                meanSaturation = meanSaturation + (cells[i].statistics.saturation * (area.D / cellArea));
            }
            //Durchschnittliche Zellfläche berechnen
            averageCellArea = Math.Round(cellArea * (1 / calibrationFactor), 2);
            double org_averageCellArea = averageCellArea;
            int unitCounter = 0;
            if (averageCellArea > 10000)
            {
                while (averageCellArea > 10000)
                {
                    if (unitCounter == 0)
                        averageCellArea = averageCellArea / 10000;
                    else
                    {
                        averageCellArea = org_averageCellArea;
                        averageCellArea = averageCellArea / 1000000;
                        org_averageCellArea = averageCellArea;
                    }
                    unitCounter++;
                }
                switch (unitCounter)
                {
                    case 1: averageCellAreaUnit = " cm²";
                        break;
                    case 2: averageCellAreaUnit = " mm²";
                        break;
                    case 3: averageCellAreaUnit = " ym²";
                        break;
                    case 4: averageCellAreaUnit = " nm²";
                        break;
                    case 5: averageCellAreaUnit = " pm²";
                        break;
                }
            }
            else
            {
                averageCellAreaUnit = " m²";
            }
            //----------------------------------------------------------------------------------
            //Anzahl lebender und toter Zellen bestimmen
            //----------------------------------------------------------------------------------
            for (int i = 0; i < geoObjects.Count; i++)
            {
                if ((geoObjects[i].Layer == 1) || (geoObjects[i].Layer == 5) || (geoObjects[i].Layer == 4))
                    totalCellCount++;
                if (geoObjects[i].Layer == 4)
                    deadCellCount++;
            }
            aliveCellCount = totalCellCount - deadCellCount;
            //----------------------------------------------------------------------------------
            //Gesamtfläche des Probenausschnittes bestimmen (in m^2) für die Berechnung der Zelldichte
            //----------------------------------------------------------------------------------
            double probeArea = 0;
            probeArea = (width * (1 / calibrationFactor)) * (height * (1 / calibrationFactor));
            //----------------------------------------------------------------------------------
            //Berechnung der Zelldichte
            //----------------------------------------------------------------------------------
            cellDensity = totalCellCount / probeArea;
            double org_cellDensity = cellDensity;

            unitCounter = 0;
            if (cellDensity > 10000)
            {
                while (cellDensity > 10000)
                {
                    if (unitCounter == 0)
                        cellDensity = cellDensity / 10000;
                    else
                    {
                        cellDensity = org_cellDensity;
                        cellDensity = cellDensity / 1000000;
                        org_cellDensity = cellDensity;
                    }
                    unitCounter++;
                }
                switch (unitCounter)
                {
                    case 1: cellDensityUnit = " Cells / cm²";
                        break;
                    case 2: cellDensityUnit = " Cells / mm²";
                        break;
                    case 3: cellDensityUnit = " Cells / ym²";
                        break;
                    case 4: cellDensityUnit = " Cells / nm²";
                        break;
                    case 5: cellDensityUnit = " Cells / pm²";
                        break;
                }
            }
            else
            {
                cellDensityUnit = " Cells / m²";
            }
        }
    }

    public static class imageWorker
    {
        public static TImage calcRGBImgSaturation(TImage img)
        {
            TImage targetImg = new TImage((Bitmap)img.Image.Clone());
            Color color;
            byte min = 0; byte max = 0;
            double saturation;
            int sat;

            for (int j = 0; j < img.Height; j++)
            {
                for (int i = 0; i < img.Width; i++)
                {
                    color = img.GetRGBPixel(i, j);
                    //Minimalwert in den Farbkanälen bestimmen
                    if ((color.R <= color.G) && (color.R <= color.B))
                    {
                        min = color.R;
                    }
                    else if ((color.G <= color.R) && (color.G <= color.B))
                    {
                        min = color.G;
                    }
                    else if ((color.B <= color.R) && (color.B <= color.G))
                    {
                        min = color.B;
                    }
                    //Maximalwert in den Farbkanälen bestimmen
                    if ((color.R >= color.G) && (color.R >= color.B))
                    {
                        max = color.R;
                    }
                    else if ((color.G >= color.R) && (color.G >= color.B))
                    {
                        max = color.G;
                    }
                    else if ((color.B >= color.R) && (color.B >= color.G))
                    {
                        max = color.B;
                    }
                    //Farbsättigung berechnen, mögliche Div durch 0 abfangen!
                    if (max > 0)
                        saturation = ((max - min) / (double)max) * 255;
                    else
                        saturation = 0;
                    sat = (int)saturation;
                    targetImg.SetPixel(i, j, (byte)sat);
                }
            }
            return targetImg;
        }
    }
}
